<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/M.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/M.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/M.png">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">
  <link rel="stylesheet" href="/lib/pace/pace-theme-minimal.min.css">
  <script src="/lib/pace/pace.min.js"></script>

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"maureen-liu.gitee.io","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":null},"back2top":{"enable":true,"sidebar":true,"scrollpercent":true},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":"valine","storage":true,"lazyload":false,"nav":null,"activeClass":"valine"},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="万丈高楼平地起 源码之前 了无密码">
<meta property="og:type" content="article">
<meta property="og:title" content="C++内存管理">
<meta property="og:url" content="https://maureen-liu.gitee.io/p/e088fcc4.html">
<meta property="og:site_name" content="Maureen&#39;s blog">
<meta property="og:description" content="万丈高楼平地起 源码之前 了无密码">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211123162931931.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211123163140279.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211123164909447.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211123165207092.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124123105329.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124135550983.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124141129889.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124142748990.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124143155408.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124144052828.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124145149853.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124150144477.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124150636765.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124151127682.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124152832598.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124160201128.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124160814340.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124161342993.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124161704922.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124163014208.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124163154368.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124163838898.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124164107910.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124164341507.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124165129141.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124165847707.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124170754560.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124170814849.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124170829734.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124170916005.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124171246154.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124171305604.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124171339945.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124174203054.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124174815564.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124174853491.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124175114746.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124175138803.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124175255474.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124180035282.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125140618799.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125140704478.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125140735808.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125140918232.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125141015958.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125141113485.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125141252710.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125145746329.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125145800725.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125172653447.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125172739037.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104112196.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104145616.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104217974.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104241003.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104305018.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104331059.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104356598.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104421546.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104457617.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104526092.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104550379.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104618773.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104733207.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104830326.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125531592.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125609783.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125620709.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125714290.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125844306.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125858791.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125922125.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125951732.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128130019900.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128130031869.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128182301209.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128182529355.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128182616941.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128205532576.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128205545429.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128205618548.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129142928374.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129142941645.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129154151108.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129154201493.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194606600.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194621587.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194632047.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194650512.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194739329.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194803230.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194816585.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194841648.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194901578.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194922520.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194942115.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195001985.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195014337.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195027869.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195044199.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195137875.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195156640.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195359755.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195444734.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195457085.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195538405.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195616271.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195649805.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208161947132.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162000111.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162011380.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162022485.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162031365.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162045656.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162055418.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162108361.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162120097.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162131822.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162141865.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162154856.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162205575.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162223294.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162233529.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162243742.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208181929620.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208181942134.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208181954504.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182007740.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182018073.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182028440.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182154525.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182206754.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182235773.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182258980.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182323656.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182311808.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182345728.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182424167.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182434533.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182506249.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182532557.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182746006.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182812810.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182833634.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182851410.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182654014.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182951952.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208183021501.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211211132840121.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208183133120.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208183157443.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208183226717.png">
<meta property="og:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208183240789.png">
<meta property="article:published_time" content="2021-11-23T08:15:12.000Z">
<meta property="article:modified_time" content="2021-12-11T06:24:47.452Z">
<meta property="article:author" content="Maureen">
<meta property="article:tag" content="侯捷">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211123162931931.png">

<link rel="canonical" href="https://maureen-liu.gitee.io/p/e088fcc4.html">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>
<script src="/lib/fireworks.js"></script>
  <title>C++内存管理 | Maureen's blog</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">Maureen's blog</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">记录学习的点点滴滴</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://maureen-liu.gitee.io/p/e088fcc4.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/stan.jpeg">
      <meta itemprop="name" content="Maureen">
      <meta itemprop="description" content="心之所向，素履以往">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Maureen's blog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          C++内存管理
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2021-11-23 16:15:12" itemprop="dateCreated datePublished" datetime="2021-11-23T16:15:12+08:00">2021-11-23</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-12-11 14:24:47" itemprop="dateModified" datetime="2021-12-11T14:24:47+08:00">2021-12-11</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/C/" itemprop="url" rel="index"><span itemprop="name">C++</span></a>
                </span>
                  ，
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/C/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/" itemprop="url" rel="index"><span itemprop="name">内存管理</span></a>
                </span>
            </span>

          
            <span class="post-meta-item" title="阅读次数" id="busuanzi_container_page_pv" style="display: none;">
              <span class="post-meta-item-icon">
                <i class="fa fa-eye"></i>
              </span>
              <span class="post-meta-item-text">阅读次数：</span>
              <span id="busuanzi_value_page_pv"></span>
            </span>
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Valine：</span>
    
    <a title="valine" href="/p/e088fcc4.html#valine-comments" itemprop="discussionUrl">
      <span class="post-comments-count valine-comment-count" data-xid="/p/e088fcc4.html" itemprop="commentCount"></span>
    </a>
  </span>
  
  <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>28k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>26 分钟</span>
            </span>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
      
      
        <blockquote>
<p>万丈高楼平地起</p>
<p>源码之前 了无密码</p>
</blockquote>
<span id="more"></span>
<h1 id="0-overview"><a class="markdownIt-Anchor" href="#0-overview"></a> 0. Overview</h1>
<h2 id="01-应具备的基础"><a class="markdownIt-Anchor" href="#01-应具备的基础"></a> 0.1 应具备的基础</h2>
<ul>
<li>曾经动态分配并使用 memory</li>
<li>曾经使用过 C++ 标准库的容器（containers）</li>
</ul>
<h2 id="02-目标"><a class="markdownIt-Anchor" href="#02-目标"></a> 0.2 目标</h2>
<p>从平地到万丈高楼，从最基础的C++语言构件到高知名度的内存管理器，彻底了解高高低低的方方面面。</p>
<h2 id="03-工具"><a class="markdownIt-Anchor" href="#03-工具"></a> 0.3 工具</h2>
<ul>
<li>Dev-C++ 5.11， with GNU 4.9.2</li>
<li>Visual C++ <span style="color:red">6.0</span></li>
</ul>
<h2 id="04-网络资源"><a class="markdownIt-Anchor" href="#04-网络资源"></a> 0.4 网络资源</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211123162931931.png" alt="network_resource"></p>
<h2 id="05-书籍"><a class="markdownIt-Anchor" href="#05-书籍"></a> 0.5 书籍</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211123163140279.png" alt="books"></p>
<h1 id="1-第一讲-primitives"><a class="markdownIt-Anchor" href="#1-第一讲-primitives"></a> 1. 第一讲 primitives</h1>
<p>本章讲解基础的用于分配内存和销毁内存的”工具“。</p>
<h2 id="11-c-应用程序"><a class="markdownIt-Anchor" href="#11-c-应用程序"></a> 1.1 C++ 应用程序</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211123164909447.png" alt="image-20211123164909447"></p>
<ul>
<li>C++ 应用程序可以通过多种方式调用内存分配的”工具“（即接口）</li>
</ul>
<h2 id="12-c-memory-primitives"><a class="markdownIt-Anchor" href="#12-c-memory-primitives"></a> 1.2 C++ memory primitives</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211123165207092.png" alt="image-20211123165207092"></p>
<h2 id="13-四个层面的基本用法"><a class="markdownIt-Anchor" href="#13-四个层面的基本用法"></a> 1.3 四个层面的基本用法</h2>
<p>对上述的 4 个 <code>primitives</code> 的使用示例：</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124123105329.png" alt="image-20211124123105329"></p>
<p>说明：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span>* p3 = ::<span class="keyword">operator</span> <span class="built_in"><span class="keyword">new</span></span>(<span class="number">512</span>); <span class="comment">//底层就是调用的malloc</span></span><br><span class="line">::<span class="function"><span class="keyword">operator</span> <span class="title">delete</span><span class="params">(p3)</span></span>; <span class="comment">//底层就是调用的free</span></span><br></pre></td></tr></table></figure>
<p>之所以用了不同的宏来区分，是因为虽然是标准接口，但在不同的环境下不同的使用方式效率不同。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> __BORLANDC__</span></span><br><span class="line">	<span class="comment">//此处的allocator&lt;int&gt;()是临时对象，该行执行结束后，对象的生命就结束了</span></span><br><span class="line">	<span class="comment">//分配5个整数，而不是5个字节，因为指定了放的单元类型</span></span><br><span class="line">    <span class="keyword">int</span>* p4 = allocator&lt;<span class="keyword">int</span>&gt;().<span class="built_in">allocate</span>(<span class="number">5</span>); </span><br><span class="line">    allocator&lt;<span class="keyword">int</span>&gt;().<span class="built_in">deallocate</span>(p4,<span class="number">5</span>);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br></pre></td></tr></table></figure>
<p>较新的GNU版本使用<code>allocator</code>：</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124135550983.png" alt="image-20211124135550983"></p>
<h2 id="14-new-expression"><a class="markdownIt-Anchor" href="#14-new-expression"></a> 1.4 new expression</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124141129889.png" alt="image-20211124141129889"></p>
<ul>
<li><code>new</code> 的操作是：分配内存，调用构造函数；</li>
<li><code>::operator new</code> 是全局的函数，而该函数可以重载，如果它被重载了，那么调用的就是重载的函数；而此处的<code>Complex</code> 类并没有重载 <code>operator new</code>，所以调用的就是全局的<code>::operator new</code>；</li>
<li>在函数<code>opeartor new</code>中可以看到，调用了<code>malloc</code>；</li>
<li>只有编译器才可以直接调用构造函数；如果程序想直接调用构造函数，可以使用 <code>palcement new</code> 的方式：<code>new(p) Complex(1,2);</code></li>
</ul>
<h2 id="15-delete-expression"><a class="markdownIt-Anchor" href="#15-delete-expression"></a> 1.5 delete expression</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124142748990.png" alt="image-20211124142748990"></p>
<ul>
<li>注意：可以直接调用析构函数；</li>
<li><code>operator delete</code> 函数底层就是调用的<code>free</code>；</li>
</ul>
<h2 id="16-ctor-dtor-直接调用"><a class="markdownIt-Anchor" href="#16-ctor-dtor-直接调用"></a> 1.6 Ctor &amp; Dtor 直接调用</h2>
<p>编写程序测试是否能直接调用构造函数和析构函数：</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124143155408.png" alt="image-20211124143155408"></p>
<ul>
<li>通过指针调用构造函数：<code>pstr-&gt;string::string(&quot;jjhou&quot;);</code> 编译会失败；</li>
<li>第二段和第三段代码是自定义的类
<ul>
<li><code>pA-&gt;A::A(3);</code> 在VC6中执行会成功，而在GCC中则会执行失败，GCC更加严谨；</li>
<li><code>A::A(5);</code> 在 VC6 中也执行成功，在GCC中执行失败</li>
<li>结论：<span style="color:red">不能直接调用构造函数</span></li>
</ul>
</li>
</ul>
<h2 id="17-array-new-array-delete"><a class="markdownIt-Anchor" href="#17-array-new-array-delete"></a> 1.7 array new, array delete</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124144052828.png" alt="image-20211124144052828"></p>
<ul>
<li>如果使用的是<code>delete pca;</code>，那么编译器会认为 <code>pca</code> 是一个对象，只会调用一次析构函数；</li>
<li><code>cookie</code>记录个数；<u><span style="color:blue">用<code>malloc</code>就会有<code>cookie</code></span></u>;</li>
<li><code>Complex</code>类中没有指针，所以其实析构函数是没有什么用的，但是好的编程观念或技巧，就是要统一，使用<code>array new</code> 就要用 <code>array delete</code>;</li>
<li><code>string</code> 类中有指针，如果使用了<code>array new</code>，就一定要使用<code>array delete</code>，否则类中的指针所指向的空间不会被销毁，就会造成内存泄漏；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124145149853.png" alt="image-20211124145149853"></p>
<ul>
<li><code>A</code>类一定要写默认构造函数，因为使用<code>array new</code> 的时候是没有办法设置初值的，调用的就是默认构造函数；</li>
<li>使用<code>placement new</code>来设置初值：<code>new (tmp++) A(i);</code> 【注：在 <code>tmp</code> 这个地址放置一个对象】</li>
</ul>
<p>小结：</p>
<ul>
<li><code>array new</code> 和 <code>array delete</code> 如果不配套写的话可能会造成内存泄漏，泄露的不是数组本身，而是类中的指针所指向的内存；</li>
<li>编译器在处理<code>array new</code> 的时候是从上往下，而<code>array delete</code> 则是从下往上；</li>
<li>注意 <code>placement new</code> 的用法；</li>
</ul>
<h2 id="18-array-sizein-memory-block"><a class="markdownIt-Anchor" href="#18-array-sizein-memory-block"></a> 1.8 array size，in memory block</h2>
<p>下图是VC6的<code>malloc</code>的内存布局：</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124150144477.png" alt="image-20211124150144477"></p>
<ul>
<li><code>61h</code> 是cookie，记录内存的大小<code>60h</code>，<code>1</code> 表示这块内存使用了；</li>
<li>此处的<code>int</code> 的析构函数是无意义的，不重要的，所以是否使用<code>array delete</code> 都可以；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124150636765.png" alt="image-20211124150636765"></p>
<ul>
<li>而<code>Demo</code>类，使用<code>array new</code> 的时候，内存中会有一个表示分配的对象个数的数，此处的<code>3</code>；</li>
<li><code>delete[] p;</code> 的时候，因为有<code>[]</code>，底层执行<code>free</code> 的时候发现对象个数是 3，于是就调用 3 次析构函数；</li>
</ul>
<h2 id="19-placement-new"><a class="markdownIt-Anchor" href="#19-placement-new"></a> 1.9 placement new</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124151127682.png" alt="image-20211124151127682"></p>
<ul>
<li><code>placement new</code> 允许我们将<code>object</code> 建构于已经分配的内存中，所以首先需要有一个指针指向已经分配的内存</li>
</ul>
<h2 id="110-c应用程序分配内存的途径"><a class="markdownIt-Anchor" href="#110-c应用程序分配内存的途径"></a> 1.10 C++应用程序，分配内存的途径</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124152832598.png" alt="image-20211124152832598"></p>
<h2 id="111-c容器分配内存的途径"><a class="markdownIt-Anchor" href="#111-c容器分配内存的途径"></a> 1.11 C++容器，分配内存的途径</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124160201128.png" alt="image-20211124160201128"></p>
<ul>
<li>将一个元素放到容器中的时候，容器也要 <code>new</code> 一块空间，来构造出来；</li>
</ul>
<h2 id="112-重载"><a class="markdownIt-Anchor" href="#112-重载"></a> 1.12 重载</h2>
<h3 id="1121-重载operator-newoperator-delete"><a class="markdownIt-Anchor" href="#1121-重载operator-newoperator-delete"></a> 1.12.1 重载::operator new/::operator delete</h3>
<ul>
<li>重载全局的<code>operator new</code>/<code>opeartor delete</code>，即类外重载：</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124160814340.png" alt="image-20211124160814340"></p>
<h3 id="1122-重载operator-newoperator-delete"><a class="markdownIt-Anchor" href="#1122-重载operator-newoperator-delete"></a> 1.12.2 重载operator new/operator delete</h3>
<ul>
<li>在类中重载：</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124161342993.png" alt="image-20211124161342993"></p>
<h3 id="1123-重载operator-newoperator-delete"><a class="markdownIt-Anchor" href="#1123-重载operator-newoperator-delete"></a> 1.12.3 重载operator new[]/operator delete[]</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124161704922.png" alt="image-20211124161704922"></p>
<h3 id="1124-重载示例"><a class="markdownIt-Anchor" href="#1124-重载示例"></a> 1.12.4 重载示例</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124163014208.png" alt="image-20211124163014208"></p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124163154368.png" alt="image-20211124163154368"></p>
<p>如果这样写：</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124163838898.png" alt="image-20211124163838898"></p>
<p>绕过了重载的函数，强制使用全局版本。</p>
<h3 id="1125-重载-newdelete"><a class="markdownIt-Anchor" href="#1125-重载-newdelete"></a> 1.12.5 重载 new()/delete()</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124164107910.png" alt="image-20211124164107910"></p>
<p>例子：</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124164341507.png" alt="image-20211124164341507"></p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124165129141.png" alt="image-20211124165129141"></p>
<ul>
<li>第⑤个<code>Foo* p5 = new(100) Foo(1)</code>调用的是<code>void* operator new(size_t size, long extra)</code> 这个函数；其调用的是带有参数的构造函数<code>Foo(int)</code>，在该构造函数中抛出了异常，只有在这种情况下（构造函数内抛出异常）对应的<code>operator delete</code>才会被调用；</li>
</ul>
<h3 id="1126-basic_string-使用-newextra-扩充申请量"><a class="markdownIt-Anchor" href="#1126-basic_string-使用-newextra-扩充申请量"></a> 1.12.6 basic_string 使用 new(<em>extra</em>) 扩充申请量</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124165847707.png" alt="image-20211124165847707"></p>
<ul>
<li>每次创建字符串的时候都多带了一包东西，所以需要<code>extra</code></li>
</ul>
<h2 id="113-allocator"><a class="markdownIt-Anchor" href="#113-allocator"></a> 1.13 allocator</h2>
<p>接下来的几个版本是我们自行开发的小型的内存分配器。</p>
<h3 id="1131-per-class-allocator"><a class="markdownIt-Anchor" href="#1131-per-class-allocator"></a> 1.13.1 per-class allocator</h3>
<h4 id="11311-v1版本"><a class="markdownIt-Anchor" href="#11311-v1版本"></a> 1.13.1.1 v1版本</h4>
<p>第一版本的<code>opeartor new</code> 和 <code>operator delete</code>:</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124170754560.png" alt="image-20211124170754560"></p>
<ul>
<li>这就是个小型的分配器（内存池），但是只针对于这个类；</li>
<li>针对的是VC6编译器中的内存块，测试：</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124170814849.png" alt="image-20211124170814849"></p>
<h4 id="11312-v2版本加上了embedded-pointer"><a class="markdownIt-Anchor" href="#11312-v2版本加上了embedded-pointer"></a> 1.13.1.2 v2版本：加上了embedded pointer</h4>
<p>第二版本的<code>operator new</code>:</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124170829734.png" alt="image-20211124170829734"></p>
<ul>
<li>
<p>说明</p>
  <figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">union</span> &#123;</span></span><br><span class="line">    AirplaneRep rep;</span><br><span class="line">    Airplane* next; </span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>其中<code>Airplane* next;</code> 借用同一个东西的前4个字节当成指针来使用，这种方法叫做“embedded pointer”，所有内存管理都用了这种技巧。</p>
  <figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">AirplaneRep</span> &#123;</span></span><br><span class="line">    <span class="keyword">unsigned</span> <span class="keyword">long</span> miles; <span class="comment">//4字节</span></span><br><span class="line">    <span class="keyword">char</span> type;<span class="comment">//1字节</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>为了内存对齐，<code>struct AirplaneRep</code>  的大小为 8 字节。</p>
  <figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt; BLOCK_SIZE - <span class="number">1</span>; i++) </span><br><span class="line">    newBlock[i].next = &amp;newBlock[i+<span class="number">1</span>]; <span class="comment">//next每次移动8个字节</span></span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>第二版本的<code>opeartor delete</code>:</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124170916005.png" alt="image-20211124170916005"></p>
<ul>
<li>将收回来的指针放入单向链表的头；但是没有还给操作系统；</li>
<li>写了<code>member operator new/delete</code>的间隔是8，从间隔可以看出，对象都是紧紧相连的，没有耗用掉<code>cookie</code>;</li>
<li>而使用<code>global opeartor new/delete</code>的，每个对象的前后都有<code>cookie</code>，所以间隔是 16；</li>
</ul>
<p>第二版本相比于第一版的优点：使用了<code>union</code> ，用前4个字节当成指针来使用，即“embedded pointer”方法。</p>
<p>但是还是有个小缺点：收回来的指针全部累计起来了，如果能还给操作系统就更好了。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*************************************************************************</span></span><br><span class="line"><span class="comment">	&gt; File Name: 01.per-class_allocator.cpp</span></span><br><span class="line"><span class="comment">	&gt; Author: Maureen </span></span><br><span class="line"><span class="comment">	&gt; Mail: Maureen@qq.com </span></span><br><span class="line"><span class="comment">	&gt; Created Time: Thu Nov 25 09:52:51 2021</span></span><br><span class="line"><span class="comment"> ************************************************************************/</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Airplane</span> &#123;</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">AirplaneRep</span> &#123;</span></span><br><span class="line">        <span class="keyword">unsigned</span> <span class="keyword">long</span> miles;</span><br><span class="line">        <span class="keyword">char</span> type;</span><br><span class="line">    &#125;;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="class"><span class="keyword">union</span> &#123;</span></span><br><span class="line">        AirplaneRep rep;</span><br><span class="line">        Airplane* next;</span><br><span class="line">    &#125;;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="title">getMiles</span><span class="params">()</span> </span>&#123; <span class="keyword">return</span> rep.miles; &#125;</span><br><span class="line">    <span class="function"><span class="keyword">char</span> <span class="title">getType</span><span class="params">()</span> </span>&#123; <span class="keyword">return</span> rep.type; &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">set</span><span class="params">(<span class="keyword">unsigned</span> <span class="keyword">long</span> m, <span class="keyword">char</span> t)</span> </span>&#123;</span><br><span class="line">        rep.miles = m;</span><br><span class="line">        rep.type = t;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">static</span> <span class="keyword">void</span>* <span class="keyword">operator</span> <span class="title">new</span><span class="params">(<span class="keyword">size_t</span> size)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="keyword">void</span>* deadObject, <span class="keyword">size_t</span> size)</span></span>;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">const</span> <span class="keyword">int</span> BLOCK_SIZE;</span><br><span class="line">    <span class="keyword">static</span> Airplane* headOfFreeList;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">Airplane* Airplane::headOfFreeList;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> Airplane::BLOCK_SIZE = <span class="number">512</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span>* Airplane::<span class="keyword">operator</span> <span class="title">new</span><span class="params">(<span class="keyword">size_t</span> size)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//如果大小有误，转交给::opeartor new(). 在继承的时候可能发现大小有误</span></span><br><span class="line">    <span class="keyword">if</span> (size != <span class="built_in"><span class="keyword">sizeof</span></span>(Airplane)) </span><br><span class="line">        <span class="keyword">return</span> ::<span class="keyword">operator</span> <span class="built_in"><span class="keyword">new</span></span>(size);</span><br><span class="line"></span><br><span class="line">    Airplane* p = headOfFreeList;</span><br><span class="line">    <span class="keyword">if</span> (p) <span class="comment">//若p有效，将list头部下移一个元素</span></span><br><span class="line">        headOfFreeList = p-&gt;next;</span><br><span class="line">    <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">//free list已空，申请（分配）一大块</span></span><br><span class="line">        Airplane* newBlock = <span class="keyword">static_cast</span>&lt;Airplane*&gt;(::<span class="keyword">operator</span> <span class="built_in"><span class="keyword">new</span></span>(BLOCK_SIZE * <span class="built_in"><span class="keyword">sizeof</span></span>(Airplane)));</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//将小块串成一个free list，但跳过 #0，因它将被传回作为本次成果</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt; BLOCK_SIZE - <span class="number">1</span>; i++) </span><br><span class="line">            newBlock[i].next = &amp;newBlock[i + <span class="number">1</span>];</span><br><span class="line">        newBlock[BLOCK_SIZE - <span class="number">1</span>].next = <span class="number">0</span>; <span class="comment">//结束list</span></span><br><span class="line">        p = newBlock;</span><br><span class="line">        headOfFreeList = &amp;newBlock[<span class="number">1</span>];</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> p;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//opeartor delete接获一个内存块</span></span><br><span class="line"><span class="comment">//如果大小正确，就把它加到free list前端</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> Airplane::<span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="keyword">void</span>* deadObject, <span class="keyword">size_t</span> size)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (deadObject == <span class="number">0</span>) <span class="keyword">return</span> ;</span><br><span class="line">    <span class="keyword">if</span> (size != <span class="built_in"><span class="keyword">sizeof</span></span>(Airplane)) &#123;</span><br><span class="line">        ::<span class="function"><span class="keyword">operator</span> <span class="title">delete</span><span class="params">(deadObject)</span></span>;</span><br><span class="line">        <span class="keyword">return</span> ;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Airplane* carcass = <span class="keyword">static_cast</span>&lt;Airplane*&gt;(deadObject);</span><br><span class="line"></span><br><span class="line">    carcass-&gt;next = headOfFreeList;</span><br><span class="line">    headOfFreeList = carcass;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="built_in"><span class="keyword">sizeof</span></span>(Airplane) &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">size_t</span> <span class="keyword">const</span> N = <span class="number">100</span>;</span><br><span class="line">    Airplane* p[N];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; N; ++i) </span><br><span class="line">        p[i] = <span class="keyword">new</span> Airplane;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//随机测试object是否正常</span></span><br><span class="line">    p[<span class="number">1</span>]-&gt;<span class="built_in">set</span>(<span class="number">1000</span>, <span class="string">&#x27;A&#x27;</span>);</span><br><span class="line">    p[<span class="number">5</span>]-&gt;<span class="built_in">set</span>(<span class="number">2000</span>, <span class="string">&#x27;B&#x27;</span>);</span><br><span class="line">    p[<span class="number">9</span>]-&gt;<span class="built_in">set</span>(<span class="number">500000</span>, <span class="string">&#x27;C&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//输出前10个pointers，用于比较其间隔</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; ++i) </span><br><span class="line">        cout &lt;&lt; p[i] &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; N; ++i) </span><br><span class="line">        <span class="keyword">delete</span> p[i];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//测试环境非侯捷的测试环境，所以结果有很大区别</span></span><br></pre></td></tr></table></figure>
<h3 id="1132-static-allocator"><a class="markdownIt-Anchor" href="#1132-static-allocator"></a> 1.13.2 static allocator</h3>
<p>特点：将内存的动作抽取到单一的class——<code>allocator</code> 中；</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124171246154.png" alt="image-20211124171246154"></p>
<ul>
<li>每次开辟的 5 个元素在内存中都是相邻的，但是这一组元素与另外开辟的 5 个元素不一定是相邻的；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124171305604.png" alt="image-20211124171305604"></p>
<h4 id="11321-static-allocator-示例与结果"><a class="markdownIt-Anchor" href="#11321-static-allocator-示例与结果"></a> 1.13.2.1 static allocator 示例与结果</h4>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124171339945.png" alt="image-20211124171339945"></p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*************************************************************************</span></span><br><span class="line"><span class="comment">	&gt; File Name: 02.static_allocator.cpp</span></span><br><span class="line"><span class="comment">	&gt; Author: Maureen </span></span><br><span class="line"><span class="comment">	&gt; Mail: Maureen@qq.com </span></span><br><span class="line"><span class="comment">	&gt; Created Time: Thu Nov 25 10:28:15 2021</span></span><br><span class="line"><span class="comment"> ************************************************************************/</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">allocator</span> &#123;</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="comment">//单向链表的节点</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">obj</span> &#123;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">obj</span>* <span class="title">next</span>;</span> <span class="comment">//embedded pointer</span></span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span>* <span class="title">allocate</span><span class="params">(<span class="keyword">size_t</span>)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">deallocate</span><span class="params">(<span class="keyword">void</span>*, <span class="keyword">size_t</span>)</span></span>;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    obj* freeStore = <span class="literal">nullptr</span>;</span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">int</span> CHUNK = <span class="number">5</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span>* <span class="title">allocator::allocate</span><span class="params">(<span class="keyword">size_t</span> size)</span> </span>&#123;</span><br><span class="line">    obj* p;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!freeStore) &#123;</span><br><span class="line">        <span class="comment">//linked list为空，于是申请一大块</span></span><br><span class="line">        <span class="keyword">size_t</span> chunk = CHUNK * size;</span><br><span class="line">        freeStore = p = (obj*)<span class="built_in">malloc</span>(chunk);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//将分配得来的一大块当做linked list般，小块小块串接起来</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; (CHUNK - <span class="number">1</span>); ++i) &#123;</span><br><span class="line">            p-&gt;next = (obj*)((<span class="keyword">char</span>*)p + size);</span><br><span class="line">            p = p-&gt;next;</span><br><span class="line">        &#125;</span><br><span class="line">        p-&gt;next = <span class="literal">nullptr</span>; <span class="comment">//last</span></span><br><span class="line">    &#125;</span><br><span class="line">    p = freeStore;</span><br><span class="line">    freeStore = freeStore-&gt;next;</span><br><span class="line">    <span class="keyword">return</span> p;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">allocator::deallocate</span><span class="params">(<span class="keyword">void</span>* p, <span class="keyword">size_t</span>)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//将 *p 收回插入 free list前端</span></span><br><span class="line">    ((obj*)p)-&gt;next = freeStore;</span><br><span class="line">    freeStore = (obj*)p;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Foo</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">long</span> L;</span><br><span class="line">    string str;</span><br><span class="line">    <span class="keyword">static</span> allocator myAlloc;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Foo</span>(<span class="keyword">long</span> l): <span class="built_in">L</span>(l) &#123;  &#125;</span><br><span class="line">    <span class="function"><span class="keyword">static</span> <span class="keyword">void</span>* <span class="keyword">operator</span> <span class="title">new</span><span class="params">(<span class="keyword">size_t</span> size)</span> </span>&#123; </span><br><span class="line">        <span class="keyword">return</span> myAlloc.<span class="built_in">allocate</span>(size); </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="keyword">void</span>* phead, <span class="keyword">size_t</span> size)</span> </span>&#123; </span><br><span class="line">        <span class="keyword">return</span> myAlloc.<span class="built_in">deallocate</span>(phead, size); </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line">allocator Foo::myAlloc;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Goo</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    complex&lt;<span class="keyword">double</span>&gt; c;</span><br><span class="line">    string str;</span><br><span class="line">    <span class="keyword">static</span> allocator myAlloc;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Goo</span>(<span class="keyword">const</span> complex&lt;<span class="keyword">double</span>&gt;&amp; x): <span class="built_in">c</span>(x) &#123;  &#125;</span><br><span class="line">    <span class="function"><span class="keyword">static</span> <span class="keyword">void</span>* <span class="keyword">operator</span> <span class="title">new</span><span class="params">(<span class="keyword">size_t</span> size)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> myAlloc.<span class="built_in">allocate</span>(size);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="keyword">void</span>* phead, <span class="keyword">size_t</span> size)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> myAlloc.<span class="built_in">deallocate</span>(phead, size);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line">allocator Goo::myAlloc;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    Foo* p[<span class="number">100</span>];</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;sizeof(Foo) = &quot;</span> &lt;&lt; <span class="built_in"><span class="keyword">sizeof</span></span>(Foo) &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">23</span>; ++i) &#123;</span><br><span class="line">        p[i] = <span class="keyword">new</span> <span class="built_in">Foo</span>(i);</span><br><span class="line">        cout &lt;&lt; p[i] &lt;&lt; <span class="string">&quot; &quot;</span> &lt;&lt; p[i]-&gt;L &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">23</span>; ++i) &#123;</span><br><span class="line">        <span class="keyword">delete</span> p[i];</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">	<span class="comment">//============</span></span><br><span class="line">    </span><br><span class="line">    Goo* p[<span class="number">100</span>];</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;sizeof(Goo) = &quot;</span> &lt;&lt; <span class="built_in"><span class="keyword">sizeof</span></span>(Goo) &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">17</span>; ++i) &#123;</span><br><span class="line">        p[i] = <span class="keyword">new</span> <span class="built_in">Goo</span>(complext&lt;<span class="keyword">double</span>&gt;(i, i));</span><br><span class="line">        cout &lt;&lt; p[i] &lt;&lt; <span class="string">&quot; &quot;</span> &lt;&lt; p[i]-&gt;c &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">17</span>; ++i) &#123;</span><br><span class="line">        <span class="keyword">delete</span> p[i];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="11322-marco-for-static-allocator"><a class="markdownIt-Anchor" href="#11322-marco-for-static-allocator"></a> 1.13.2.2 marco for static allocator</h4>
<p>因为每个使用<code>allocator</code> 的类的几处写法是固定的，于是将它们写成宏：</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124174203054.png" alt="image-20211124174203054"></p>
<p>示例与结果：</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124174815564.png" alt="image-20211124174815564"></p>
<p>代码：</p>
<ul>
<li>宏</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//DECLARE_POOL_ALLOC -- used in class definition</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> DECLARE_POOL_ALLOC()\</span></span><br><span class="line"><span class="meta">public:\</span></span><br><span class="line"><span class="meta">    void* operator new(size_t size) &#123; return myAlloc.allocate(size); &#125;\</span></span><br><span class="line"><span class="meta">    void operator delete(void* p) &#123; myAlloc.deallocate(p, 0); &#125;\</span></span><br><span class="line"><span class="meta">protected:\</span></span><br><span class="line"><span class="meta">    static allocator myAlloc;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//IMPLEMENT_POOL_ALLOC -- used in class implementation</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> IMPLEMENT_POOL_ALLOC(class_name)\</span></span><br><span class="line"><span class="meta">allocator class_name::myAlloc</span></span><br></pre></td></tr></table></figure>
<ul>
<li><code>Foo</code></li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Foo</span> &#123;</span></span><br><span class="line">    <span class="built_in">DECLARE_POOL_ALLOC</span>()</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">long</span> L;</span><br><span class="line">    string str;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Foo</span>(<span class="keyword">long</span> l): <span class="built_in">L</span>(l) &#123;  &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="built_in">IMPLEMENT_POOL_ALLOC</span>(Foo)</span><br></pre></td></tr></table></figure>
<ul>
<li><code>Goo</code></li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Goo</span> &#123;</span></span><br><span class="line">    <span class="built_in">DECLARE_POOL_ALLOC</span>()</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    complex&lt;<span class="keyword">double</span>&gt; c;</span><br><span class="line">    string str;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Goo</span>(<span class="keyword">const</span> complex&lt;<span class="keyword">double</span>&gt;&amp; x): <span class="built_in">c</span>(x) &#123;  &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="built_in">IMPLEMENT_POOL_ALLOC</span>(Goo)</span><br></pre></td></tr></table></figure>
<h3 id="1133-global-allocatorwith-multiple-free-lists"><a class="markdownIt-Anchor" href="#1133-global-allocatorwith-multiple-free-lists"></a> 1.13.3 global allocator（with multiple free-lists)</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124174853491.png" alt="image-20211124174853491"></p>
<p>是static allocator的进阶版，针对所有的class，而非针对单一的class。不是用<code>static</code>变量的方式使用<code>allocator</code>，而是全局的。</p>
<h3 id="1134-小结"><a class="markdownIt-Anchor" href="#1134-小结"></a> 1.13.4 小结</h3>
<ul>
<li>per-class allocator v1：一般</li>
<li>per-class allocator v2：加上了embedded pointer</li>
<li>static allocator：将内存的动作抽取到了单一的class——<code>allocator</code>中</li>
<li>marco for static allocator：设计一个 marco 宏，简化书写</li>
<li>global allocator：是static allocator的进阶版，是一个全局的<code>allocator</code></li>
</ul>
<h2 id="114-new-handler"><a class="markdownIt-Anchor" href="#114-new-handler"></a> 1.14 new handler</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124175114746.png" alt="image-20211124175114746"></p>
<ul>
<li><code>_callnewh</code>就会调用到由用户指定的<code>handler</code>；</li>
<li>如果调用到了用户指定的<code>handler</code>，说明没有内存可用了，就要在这个<code>handler</code>里让更多的内存可用：查看哪些内存可以释放；</li>
</ul>
<p>例子：</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124175138803.png" alt="image-20211124175138803"></p>
<h2 id="115-defaultdelete"><a class="markdownIt-Anchor" href="#115-defaultdelete"></a> 1.15 =default，=delete</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124175255474.png" alt="image-20211124175255474"></p>
<ul>
<li>
<p>有默认版本的函数才可以被设置为<code>default</code>，C++中有默认版本的函数</p>
<ul>
<li>
<p>拷贝构造函数</p>
</li>
<li>
<p>拷贝赋值函数</p>
</li>
<li>
<p>析构函数</p>
</li>
</ul>
</li>
<li>
<p>验证<code>operator new</code> 和 <code>operator delete</code> 是否也能 default 和 delete：</p>
</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211124180035282.png" alt="image-20211124180035282"></p>
<p>​	说明：<code>operator new</code> 和 <code>operator delte</code> 都不能设置为<code>default</code></p>
<h1 id="2-第二讲-stdallocator"><a class="markdownIt-Anchor" href="#2-第二讲-stdallocator"></a> 2. 第二讲 std::allocator</h1>
<blockquote>
<p>西北有高楼</p>
<p>上与浮云齐</p>
</blockquote>
<h2 id="21-vc6-malloc"><a class="markdownIt-Anchor" href="#21-vc6-malloc"></a> 2.1 VC6 malloc()</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125140618799.png" alt="image-20211125140618799"></p>
<ul>
<li><code>cookie</code> 主要记录当前分配的内存块的大小；</li>
<li>VC6下<code>cookie</code> 占用的大小是 8 个字节；</li>
<li>假设对象很小，但是对象很多，那么就会有大量的<code>cookie</code>，消耗了大量的内存；</li>
<li>内存管理的目标：提高效率，精简空间</li>
<li>是否有办法将<code>cookie</code> 去除呢？</li>
</ul>
<h2 id="22-不同编译器的标准分配器的实现"><a class="markdownIt-Anchor" href="#22-不同编译器的标准分配器的实现"></a> 2.2 不同编译器的标准分配器的实现</h2>
<h3 id="221-vc6-标准分配器之实现"><a class="markdownIt-Anchor" href="#221-vc6-标准分配器之实现"></a> 2.2.1 VC6 标准分配器之实现</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125140704478.png" alt="image-20211125140704478"></p>
<ul>
<li>调用流程：<code>allocate</code>-&gt;<code>_Allocate</code>-&gt; <code>operator new</code>-&gt; <code>malloc</code></li>
<li>VC6编译器里面的<code>allocator</code> 并没有做任何内存管理，只是将<code>malloc</code>以<code>allocate</code> 的样子呈现出来；</li>
<li>VC6的 <code>allocator</code> 只是以 <code>::operator new</code> 和 <code>::operator delete</code> 完成 <code>allocate()</code> 和 <code>deallocate()</code> ，没有任何特殊设计；</li>
<li>VC下的容器的第二个模板参数都是<code>allocator</code>，所以VC6下使用容器，则最终内存分配都是靠<code>malloc</code> 获得的，而<code>malloc</code> 所分配的内存块中带着 <code>cookie</code>；</li>
<li>此处的分配是以指定的元素的类型为单位</li>
</ul>
<h3 id="222-bc5-标准分配器之实现"><a class="markdownIt-Anchor" href="#222-bc5-标准分配器之实现"></a> 2.2.2 BC5 标准分配器之实现</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125140735808.png" alt="image-20211125140735808"></p>
<ul>
<li>调用流程：<code>allocate</code>-&gt;<code>::operator new</code>-&gt; <code>malloc</code></li>
<li>BC5 的 <code>allocator</code> 只是以 <code>::operator new</code> 和 <code>::operator delete</code> 完成 <code>allocate()</code> 和 <code>deallocate()</code> ，没有任何特殊设计；</li>
<li>容器里使用的分配器就是<code>allocator</code>，即获取到的内存块也是通过<code>malloc</code>分配的，该内存块是带着<code>cookie</code> 的；</li>
</ul>
<p>我们的目标是要去除<code>cookie</code>，而去除<code>cookie</code> 有个先决条件，内存块的大小一样。</p>
<h3 id="223-g29-标准分配器之实现"><a class="markdownIt-Anchor" href="#223-g29-标准分配器之实现"></a> 2.2.3 G2.9 标准分配器之实现</h3>
<h4 id="2231-stdallocator的实现"><a class="markdownIt-Anchor" href="#2231-stdallocator的实现"></a> 2.2.3.1 std::allocator的实现</h4>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125140918232.png" alt="image-20211125140918232"></p>
<ul>
<li>调用流程：<code>allocate</code>-&gt; <code>::allocate</code>-&gt;<code>::operator new</code>-&gt;<code>malloc</code></li>
<li>G2.9 的 <code>allocator</code> 只是以 <code>::operator new</code> 和 <code>::operator delete</code> 完成 <code>allocate()</code> 和 <code>deallocate()</code> ，没有任何特殊设计；</li>
<li>STL 中使用的不是这个分配器，这个文件并没有被包含到任何的STL头文件中；</li>
</ul>
<h4 id="2232-g29-容器使用的分配器不是-stdspan-stylecolorpurpleallocatorspan-而是-stdspan-stylecolorpurpleallocspan"><a class="markdownIt-Anchor" href="#2232-g29-容器使用的分配器不是-stdspan-stylecolorpurpleallocatorspan-而是-stdspan-stylecolorpurpleallocspan"></a> 2.2.3.2 G2.9 容器使用的分配器，不是 std::<span style="color:purple">allocator</span> 而是 std::<span style="color:purple">alloc</span></h4>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125141015958.png" alt="image-20211125141015958"></p>
<ul>
<li>G2.9 容器使用的分配器是<code>std::alloc</code>；</li>
<li><code>alloc</code> 是个类，<code>alloc::allocate</code>说明<code>allocate</code>是<code>alloc</code>这个类的静态函数；</li>
<li>分配单位是字节</li>
</ul>
<h4 id="2232-g29-stdspan-stylecolorpurpleallocspan-vs-g49span-stylecolorpurple__pool_allocspan"><a class="markdownIt-Anchor" href="#2232-g29-stdspan-stylecolorpurpleallocspan-vs-g49span-stylecolorpurple__pool_allocspan"></a> 2.2.3.2 (G2.9) std::<span style="color:purple">alloc</span> vs. (G4.9)<span style="color:purple">__pool_alloc</span></h4>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125141113485.png" alt="image-20211125141113485"></p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125141252710.png" alt="image-20211125141252710"></p>
<ul>
<li>
<p>使用方法</p>
<ul>
<li>G2.9版本的<code>std::alloc</code>，写法：</li>
</ul>
  <figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vector&lt;string, std::alloc&lt;string&gt;&gt; vec;</span><br></pre></td></tr></table></figure>
<ul>
<li>G4.9版本的<code>__pool_alloc</code>，写法：</li>
</ul>
  <figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vector&lt;string, __gnu_cxx::__pool_alloc&lt;string&gt;&gt; vec;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>G4.9 标准库中有很多扩充的<code>allocator</code></p>
</li>
</ul>
<h3 id="224-g49-标准分配器之实现"><a class="markdownIt-Anchor" href="#224-g49-标准分配器之实现"></a> 2.2.4 G4.9 标准分配器之实现</h3>
<h4 id="2241-stdallocator的实现"><a class="markdownIt-Anchor" href="#2241-stdallocator的实现"></a> 2.2.4.1 std::allocator的实现</h4>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125145746329.png" alt="image-20211125145746329"></p>
<ul>
<li>”标准分配器“说的就是<code>std::allocator</code>；</li>
<li>调用流程：<code>allocate</code>-&gt;<code>::operator new</code>-&gt;<code>malloc</code>；</li>
<li>G4.9 的 <code>allocator</code> 只是以 ::operator new 和 ::operator delete 完成 allocate() 和 deallocate()，没有任何特殊设计；</li>
</ul>
<h4 id="2242-pool-allocator使用示例"><a class="markdownIt-Anchor" href="#2242-pool-allocator使用示例"></a> 2.2.4.2 pool allocator使用示例</h4>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125145800725.png" alt=" "></p>
<ul>
<li>使用<code>__pool_alloc</code>去除了 <code>cookie</code>，如果 100 万个元素，去除<code>cookie</code>，就省掉了 800 万个字节，这个数据量很大了；</li>
<li>可以看到使用<code>std::allocator</code>的时候，每个元素之间相差<code>10h</code>，即16个字节，元素本身的大小为8字节，因为头尾带了cookie，所以元素之间相距 16 字节，符合我们看到的内存块；</li>
<li>某一次使用<code>__gun_cxx::__pool_alloc</code>的结果，指针之间相差不是 08h，并不能推翻分配的内存块不带 cookie 这个结论，因为是进行了 3 次分配，可能分配的内存块并不连续；</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;vector&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;ext/pool_allocator.h&gt;</span> <span class="comment">//mac使用的编译器是clang，找不到这个文件</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> Alloc&gt;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">cookie_test</span><span class="params">(Alloc alloc, <span class="keyword">size_t</span> n)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">typename</span> Alloc::value_type *p1, *p2, *p3;</span><br><span class="line"></span><br><span class="line">    p1 = alloc.<span class="built_in">allocate</span>(n);</span><br><span class="line">    p2 = alloc.<span class="built_in">allocate</span>(n);</span><br><span class="line">    p3 = alloc.<span class="built_in">allocate</span>(n);</span><br><span class="line"></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;p1 = &quot;</span> &lt;&lt; p1 &lt;&lt; <span class="string">&#x27;\t&#x27;</span> &lt;&lt; <span class="string">&quot;p2 = &quot;</span> &lt;&lt; p2 &lt;&lt; <span class="string">&#x27;\t&#x27;</span> &lt;&lt; <span class="string">&quot;p3 = &quot;</span> &lt;&lt; p3 &lt;&lt; <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    alloc.<span class="built_in">deallocate</span>(p1, <span class="built_in"><span class="keyword">sizeof</span></span>(<span class="keyword">typename</span> Alloc::value_type));</span><br><span class="line">    alloc.<span class="built_in">deallocate</span>(p2, <span class="built_in"><span class="keyword">sizeof</span></span>(<span class="keyword">typename</span> Alloc::value_type));</span><br><span class="line">    alloc.<span class="built_in">deallocate</span>(p3, <span class="built_in"><span class="keyword">sizeof</span></span>(<span class="keyword">typename</span> Alloc::value_type));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="built_in"><span class="keyword">sizeof</span></span>(__gnu_cxx::__pool_alloc&lt;<span class="keyword">int</span>&gt;) &lt;&lt; endl; <span class="comment">//1，本来应该是0，但是因为一些限制，只能是1</span></span><br><span class="line">    vector&lt;<span class="keyword">int</span>, __gnu_cxx::__pool_alloc&lt;<span class="keyword">int</span>&gt;&gt; vecPool;</span><br><span class="line">    <span class="built_in">cookie_test</span>(__gnu_cxx::__pool_alloc&lt;<span class="keyword">double</span>&gt;(), <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    vector&lt;<span class="keyword">int</span>, std::allocator&lt;<span class="keyword">int</span>&gt;&gt; vec;</span><br><span class="line">    <span class="built_in">cookie_test</span>(std::allocator&lt;<span class="keyword">double</span>&gt;(), <span class="number">1</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="225-小结"><a class="markdownIt-Anchor" href="#225-小结"></a> 2.2.5 小结</h3>
<p>各种编译器的标准分配器底层都是使用的<code>malloc</code>进行内存分配，分配的内存块是带着<code>cookie</code> 的，G2.9 和 G4.9 存在着比标准分配器更优秀的 extended allocator。</p>
<h2 id="23-g29-stdalloc-运行模式"><a class="markdownIt-Anchor" href="#23-g29-stdalloc-运行模式"></a> 2.3 G2.9 std::alloc 运行模式</h2>
<p>G4.9版本和G2.9版本是一样的，只是G4.9的写法更为复杂一些，所以为了方便，看G2.9版本足以。</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125172653447.png" alt="image-20211125172653447"></p>
<ul>
<li>G2.9的容器使用的分配器是<code>std::alloc</code>；</li>
<li>分配器一定要提供两个重要的函数：
<ul>
<li><code>allocate</code> （分配）</li>
<li><code>deallocate</code> （回收）</li>
</ul>
</li>
<li>16条链表，超过这个链表最大管理的内存块大小范围（128bytes）的内存分配不再受<code>std::alloc</code>管理，而是通过<code>malloc</code>进行分配；</li>
<li>#0 串联 8 字节的内存块，#1 串联 16 字节的内存块，#2 串联 24 字节的内存块… 链表间的内存块相差 8 字节；</li>
<li>如果容器中的每个元素需求的内存块的大小不是8的倍数，比如需要6，则进入<code>std::alloc</code>这个系统后，会被调成8；这个设计在所有的分配器上都一样，<code>malloc</code>也是这样的设计；</li>
<li>如果使用容器1，每个元素的大小都是 32 字节，#3 是管理32字节的内存块的，一开始#3 是空的，它就会去挖一块 20 * 32 大小的内存以备使用（20应该是开发<code>std::alloc</code>的人员的经验值）；当这 20块 32字节的内存使用完之后，又会再要 20 * 32 字节大小的内存，以此类推；</li>
<li>实际上挖的大小是 20 * 2 * 32字节，而一半拿来切 32 字节的内存块，另一半空置等待使用。若此时使用另一个容器2，每个元素的大小是 64 字节，则需要 #7 链表来管理 64 字节的内存块，当 #7 链表需要的时候，将剩余的 20 * 32 切割成每个内存块 64 字节的大小，可以切出 10 个，可以看到它们 #3 和 #7 的内存块是相连的；至此，分配的内存都使用完了；</li>
<li>如果此时再使用一个容器3，每个元素大小为 96，容器向分配器要 96 个字节，这个大小的内存块由 #11 管理，当前 #11 是空的，且没有可以切割的内存，于是向系统要 20 * 2 * 96 字节的内存，同样地，一半用于切割成 20 个 96 字节的内存块，一半空闲以备使用，即图中的<code>start_free ~ end_free</code>这一段内存；</li>
<li>容器不再需要元素的时候，要归还内存，根据内存大小就回收到负责该大小的内存块的链表上；</li>
<li>如果容器中的每个元素的大小为 256bytes，超出了链表的内存块的范围，则这些内存的分配就不再归<code>std::alloc</code> 管理，而是调用<code>malloc</code> 进行分配，将分配得到的空间传回给容器；</li>
<li>容器每次通过动态分配得到指针，容器本身是不知道分配得到的内存是否带cookie；</li>
<li><code>std::alloc</code>里管理的内存块都是没有cookie的；当然链表为空时，向系统申请的 20 * 2 * x 字节是通过<code>malloc</code>申请的，</li>
</ul>
<h3 id="embedded-pointers"><a class="markdownIt-Anchor" href="#embedded-pointers"></a> embedded pointers</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211125172739037.png" alt="image-20211125172739037"></p>
<ul>
<li>
<p>链表借用每个内存块的前 4 个字节，作为一个指针；</p>
</li>
<li>
<p>当将内存块给到客户时，前面的 4 个字节是会被容器中的数据填充的；当内存块被归还的时候，又会将前 4 个字节作为一个指针；</p>
</li>
<li>
<p>所有的有商业价值的、设计好的内存管理一定是使用了embedded pointer；</p>
</li>
<li>
<p>借用4个字节作为embedded pointer在源代码中的设计：</p>
  <figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">union</span> <span class="title">obj</span> &#123;</span> <span class="comment">//也可以该用struct，就是链表的节点</span></span><br><span class="line">  <span class="class"><span class="keyword">union</span> <span class="title">obj</span>* <span class="title">free_list_link</span>;</span></span><br><span class="line">  <span class="keyword">char</span> client_data[<span class="number">1</span>]; <span class="comment">//没有使用到</span></span><br><span class="line">&#125;; </span><br></pre></td></tr></table></figure>
</li>
<li>
<p>对象本身大于等于4bytes才能被借用，如果内存块的size小于4bytes，则不能借用了；虽然工业级存在海量的小区块，但是这些小区块多半都是大于4bytes的，所以多半可以借用；</p>
</li>
</ul>
<h3 id="g29-stdalloc-运行一瞥01"><a class="markdownIt-Anchor" href="#g29-stdalloc-运行一瞥01"></a> G2.9 std::alloc 运行一瞥.01</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104112196.png" alt="image-20211126104112196"></p>
<ul>
<li>定义了 16 个指针，一开始全部为空；</li>
</ul>
<h3 id="g29-stdalloc-运行一瞥02"><a class="markdownIt-Anchor" href="#g29-stdalloc-运行一瞥02"></a> G2.9 std::alloc 运行一瞥.02</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104145616.png" alt="image-20211126104145616"></p>
<ul>
<li>此处的申请 32 bytes，是应用端使用了容器，容器向分配器申请了 32bytes；</li>
<li>分配器的客户是容器，而不是程序员写的程序，如果程序员向直接使用分配器，必须记住申请的内存的大小，归还的时候将大小进行告知。而容器中的元素大小是相同的，容器的第一个模板参数是类型，<code>sizeof(类型)</code> 就可以知道元素的大小；</li>
<li><code>RoundUp</code>是个函数，将数字调到16的倍数，该值是个追加量：<code>RoundUp(0&gt;&gt;4)</code> 中的<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>0</mn><mo>&gt;</mo><mo>&gt;</mo><mn>4</mn></mrow><annotation encoding="application/x-tex">0&gt;&gt;4</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68354em;vertical-align:-0.0391em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span></span><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">4</span></span></span></span> 就是0除以16；</li>
<li>图中的这一整块是用<code>malloc</code>分配的，所以头尾都有cookie；</li>
<li>pool 就是依靠 <code>start_free</code> 和 <code>end_free</code> 这两个指针围起来的；</li>
</ul>
<h3 id="g29-stdalloc运行一瞥03"><a class="markdownIt-Anchor" href="#g29-stdalloc运行一瞥03"></a> G2.9 std::alloc运行一瞥.03</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104217974.png" alt="image-20211126104217974"></p>
<ul>
<li>接上页，此时容器申请64bytes，使用上页中的 <code>pool</code> 进行切割；</li>
</ul>
<h3 id="g29-stdalloc运行一瞥04"><a class="markdownIt-Anchor" href="#g29-stdalloc运行一瞥04"></a> G2.9 std::alloc运行一瞥.04</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104241003.png" alt="image-20211126104241003"></p>
<ul>
<li>容器申请 96个字节，#11 链表是空的，而且<code>pool</code> 此时是空的，所以用<code>malloc</code>分配 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>90</mn><mo>×</mo><mn>20</mn><mo>×</mo><mn>2</mn><mo>+</mo><mi>R</mi><mi>o</mi><mi>u</mi><mi>n</mi><mi>d</mi><mi>U</mi><mi>p</mi><mo stretchy="false">(</mo><mn>1280</mn><mo>&gt;</mo><mo>&gt;</mo><mn>4</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">90 \times 20 \times 2 + RoundUp(1280&gt;&gt;4)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">9</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">2</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.00773em;">R</span><span class="mord mathdefault">o</span><span class="mord mathdefault">u</span><span class="mord mathdefault">n</span><span class="mord mathdefault">d</span><span class="mord mathdefault" style="margin-right:0.10903em;">U</span><span class="mord mathdefault">p</span><span class="mopen">(</span><span class="mord">1</span><span class="mord">2</span><span class="mord">8</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span></span><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span></span></span></span> 大小的内存，分配的内存前后都有cookie，注意<code>RoundUp</code> 后面的参数就是 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi mathvariant="normal">累</mi><mi mathvariant="normal">计</mi><mi mathvariant="normal">申</mi><mi mathvariant="normal">请</mi><mi mathvariant="normal">量</mi><mo>&gt;</mo><mo>&gt;</mo><mn>4</mn><mo>=</mo><mi mathvariant="normal">累</mi><mi mathvariant="normal">计</mi><mi mathvariant="normal">申</mi><mi mathvariant="normal">请</mi><mi mathvariant="normal">量</mi><mtext> </mtext><mi mathvariant="normal">/</mi><mtext> </mtext><mn>16</mn></mrow><annotation encoding="application/x-tex">累计申请量 &gt;&gt; 4 = 累计申请量 \ / \ 16</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"></span><span class="mord cjk_fallback">累</span><span class="mord cjk_fallback">计</span><span class="mord cjk_fallback">申</span><span class="mord cjk_fallback">请</span><span class="mord cjk_fallback">量</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span></span><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">4</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord cjk_fallback">累</span><span class="mord cjk_fallback">计</span><span class="mord cjk_fallback">申</span><span class="mord cjk_fallback">请</span><span class="mord cjk_fallback">量</span><span class="mspace"> </span><span class="mord">/</span><span class="mspace"> </span><span class="mord">1</span><span class="mord">6</span></span></span></span>，追加量会越来越大；</li>
</ul>
<h3 id="g29-stdalloc运行一瞥05"><a class="markdownIt-Anchor" href="#g29-stdalloc运行一瞥05"></a> G2.9 std::alloc运行一瞥.05</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104305018.png" alt="image-20211126104305018"></p>
<ul>
<li>在代码中又创建了一个容器，申请88字节，#10号链表管理的内存块大小，此时#10 为空，但是<code>pool</code> 中还有余量，于是从<code>pool</code> 中进行划分；</li>
</ul>
<h3 id="g29-stdalloc运行一瞥06"><a class="markdownIt-Anchor" href="#g29-stdalloc运行一瞥06"></a> G2.9 std::alloc运行一瞥.06</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104331059.png" alt="image-20211126104331059"></p>
<ul>
<li>不在应用端再创建容器，而是某个容器连续三次申请 88，直接从 #10 链表里取出</li>
</ul>
<h3 id="g29-stdalloc运行一瞥07"><a class="markdownIt-Anchor" href="#g29-stdalloc运行一瞥07"></a> G2.9 std::alloc运行一瞥.07</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104356598.png" alt="image-20211126104356598"></p>
<ul>
<li>在客户端又建立一个容器，申请8，#0 为空，但是 pool 中还余 240，由于最多切 20 个，所以 pool 中还剩 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>240</mn><mo>−</mo><mn>20</mn><mo>×</mo><mn>8</mn><mo>=</mo><mn>80</mn></mrow><annotation encoding="application/x-tex">240 - 20 \times 8 = 80</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">2</span><span class="mord">4</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">2</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">8</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">8</span><span class="mord">0</span></span></span></span>；</li>
</ul>
<h3 id="g29-stdalloc运行一瞥08"><a class="markdownIt-Anchor" href="#g29-stdalloc运行一瞥08"></a> G2.9 std::alloc运行一瞥.08</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104421546.png" alt="image-20211126104421546"></p>
<ul>
<li>如果不同的容器申请的内存块大小相同，那么它们就会共用同一个链表；</li>
<li>此时再创建一个新的容器，申请 104，由 #12 链表管理，此时#12 为空，且 pool 中只有 80，不够；</li>
<li>先处理这80bytes的余量，80bytes应该归 list#9 管理，所以将 pool 中的 80 拨给 list #9；</li>
<li>然后再通过<code>malloc</code>分配 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>104</mn><mo>×</mo><mn>20</mn><mo>×</mo><mn>2</mn><mo>+</mo><mi>R</mi><mi>o</mi><mi>u</mi><mi>n</mi><mi>d</mi><mi>U</mi><mi>p</mi><mo stretchy="false">(</mo><mn>5200</mn><mo>&gt;</mo><mo>&gt;</mo><mn>4</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">104 \times 20 \times 2 + RoundUp(5200&gt;&gt;4)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mord">0</span><span class="mord">4</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">2</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.00773em;">R</span><span class="mord mathdefault">o</span><span class="mord mathdefault">u</span><span class="mord mathdefault">n</span><span class="mord mathdefault">d</span><span class="mord mathdefault" style="margin-right:0.10903em;">U</span><span class="mord mathdefault">p</span><span class="mopen">(</span><span class="mord">5</span><span class="mord">2</span><span class="mord">0</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span></span><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span></span></span></span> 的内存大小；划分出 20 个 104，将最开头的那个给容器；</li>
</ul>
<h3 id="g29-stdalloc运行一瞥09"><a class="markdownIt-Anchor" href="#g29-stdalloc运行一瞥09"></a> G2.9 std::alloc运行一瞥.09</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104457617.png" alt="image-20211126104457617"></p>
<h3 id="g29-stdalloc运行一瞥10"><a class="markdownIt-Anchor" href="#g29-stdalloc运行一瞥10"></a> G2.9 std::alloc运行一瞥.10</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104526092.png" alt="image-20211126104526092"></p>
<h3 id="g29-stdalloc运行一瞥11"><a class="markdownIt-Anchor" href="#g29-stdalloc运行一瞥11"></a> G2.9 std::alloc运行一瞥.11</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104550379.png" alt="image-20211126104550379"></p>
<ul>
<li>此处修改了系统源码将系统内存大小设置为了 10000；</li>
<li>因为系统内存边界是10000，此次申请的内存大小为 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>72</mn><mo>×</mo><mn>20</mn><mo>×</mo><mn>2</mn><mo>+</mo><mi>R</mi><mi>o</mi><mi>u</mi><mi>n</mi><mi>d</mi><mi>U</mi><mi>p</mi><mo stretchy="false">(</mo><mn>9688</mn><mo>&gt;</mo><mo>&gt;</mo><mn>4</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">72 \times 20 \times 2 + RoundUp(9688&gt;&gt;4)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">7</span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">2</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.00773em;">R</span><span class="mord mathdefault">o</span><span class="mord mathdefault">u</span><span class="mord mathdefault">n</span><span class="mord mathdefault">d</span><span class="mord mathdefault" style="margin-right:0.10903em;">U</span><span class="mord mathdefault">p</span><span class="mopen">(</span><span class="mord">9</span><span class="mord">6</span><span class="mord">8</span><span class="mord">8</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span></span><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span></span></span></span> ，无法满足，于是找到距离 72bytes 最近的 80bytes，即 list#9管理的内存块，可以发现 list#9 中有一个 80bytes 的内存块，于是将其回填到 pool 中，list #9变为空，再从80bytes这个内存块中切出 72 给客户，剩余 8；</li>
</ul>
<h3 id="g29-stdalloc运行一瞥12"><a class="markdownIt-Anchor" href="#g29-stdalloc运行一瞥12"></a> G2.9 std::alloc运行一瞥.12</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104618773.png" alt="image-20211126104618773"></p>
<h3 id="g29-stdalloc运行一瞥13"><a class="markdownIt-Anchor" href="#g29-stdalloc运行一瞥13"></a> G2.9 std::alloc运行一瞥.13</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104733207.png" alt="image-20211126104733207"></p>
<ul>
<li>申请 120，索取<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>120</mn><mo>∗</mo><mn>20</mn><mo>∗</mo><mn>2</mn><mo>+</mo><mi>R</mi><mi>o</mi><mi>u</mi><mi>n</mi><mi>d</mi><mi>U</mi><mi>p</mi><mo stretchy="false">(</mo><mn>9688</mn><mo>&gt;</mo><mo>&gt;</mo><mn>4</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">120*20*2+RoundUp(9688&gt;&gt;4)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord">2</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.00773em;">R</span><span class="mord mathdefault">o</span><span class="mord mathdefault">u</span><span class="mord mathdefault">n</span><span class="mord mathdefault">d</span><span class="mord mathdefault" style="margin-right:0.10903em;">U</span><span class="mord mathdefault">p</span><span class="mopen">(</span><span class="mord">9</span><span class="mord">6</span><span class="mord">8</span><span class="mord">8</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span></span><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span></span></span></span>  失败，于是找最近接它的list#5看是否有可用的区块，结果发现list#5是空的，越是找不到可用的内存，此次操作失败，申请不到120bytes的区块给客户；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211126104830326.png" alt="image-20211126104830326"></p>
<h2 id="24-g29-stdalloc-源码剖析"><a class="markdownIt-Anchor" href="#24-g29-stdalloc-源码剖析"></a> 2.4 G2.9 std::alloc 源码剖析</h2>
<h3 id="g29-stdalloc源码剖析1"><a class="markdownIt-Anchor" href="#g29-stdalloc源码剖析1"></a> G2.9 std::alloc源码剖析，1</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125531592.png" alt="image-20211128125531592"></p>
<ul>
<li>之前讲的核心的都在“第二级分配器”中，如果第二级分配器分配失败就会到第一级分配器中再试一次；</li>
<li>第一级分配器模拟 new handler，通过一个循环不断地给你机会去分配；</li>
<li>G4.9中已经没有这个第一级分配了，所以此处跳过这个讲解；</li>
</ul>
<h3 id="g29-stdalloc源码剖析2"><a class="markdownIt-Anchor" href="#g29-stdalloc源码剖析2"></a> G2.9 std::alloc源码剖析，2</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125609783.png" alt="image-20211128125609783"></p>
<h3 id="g29-stdalloc源码剖析3"><a class="markdownIt-Anchor" href="#g29-stdalloc源码剖析3"></a> G2.9 std::alloc源码剖析，3</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125620709.png" alt="image-20211128125620709"></p>
<ul>
<li>到 #74 行，第一级分配器代码完毕；</li>
</ul>
<h3 id="g29-stdalloc源码剖析4"><a class="markdownIt-Anchor" href="#g29-stdalloc源码剖析4"></a> G2.9 std::alloc源码剖析，4</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125714290.png" alt="image-20211128125714290"></p>
<ul>
<li>
<p>第二级分配器从 #90 行开始；</p>
</li>
<li>
<p><code>ROUND_UP</code>为上调函数，调整为 8 的倍数；</p>
</li>
<li>
<p>嵌入式指针：</p>
  <figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">union</span> <span class="title">obj</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">union</span> <span class="title">obj</span>* <span class="title">free_list_link</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>所有的数据和函数都是静态的；</p>
</li>
<li>
<p><code>FREELIST_INDEX</code> 函数计算出申请的内存块应该由第几号链表提供；</p>
</li>
<li>
<p><code>refill</code> 函数就是当链表为空的时候，要进行充值（即申请一大块内存）；</p>
</li>
<li>
<p><code>chunk_alloc</code> 函数申请一大块内存；</p>
</li>
</ul>
<h3 id="g29-stdalloc源码剖析5"><a class="markdownIt-Anchor" href="#g29-stdalloc源码剖析5"></a> G2.9 std::alloc源码剖析，5</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125844306.png" alt="image-20211128125844306"></p>
<ul>
<li><code>my_free_list</code>变量为指针的指针；</li>
<li>当申请的内存的大小大于 128 bytes的时候，就改用第一级分配器；</li>
<li>其中<code>my_free_list = free_list + FREELIST_INDEX(n);</code> 表示定位到是第几号链表；</li>
<li><code>*my_free_list = result-&gt;free_list_link;</code> 表示将第一块内存块给到客户，并向下移动指针；</li>
<li>如果<code>result == 0</code> ，即链表为空，则要申请一大块内存；</li>
<li><code>deallocate</code>没有将内存还给操作系统，而是将申请到的内存全部掌握在自己手中，这不是内存泄漏，但是这种做法是有争议的；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125858791.png" alt="image-20211128125858791"></p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125922125.png" alt="image-20211128125922125"></p>
<h3 id="g29-stdalloc源码剖析6"><a class="markdownIt-Anchor" href="#g29-stdalloc源码剖析6"></a> G2.9 std::alloc源码剖析，6</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128125951732.png" alt="image-20211128125951732"></p>
<ul>
<li><code>chunk_alloc</code>分配一大块内存；</li>
</ul>
<h3 id="g29-stdalloc源码剖析7"><a class="markdownIt-Anchor" href="#g29-stdalloc源码剖析7"></a> G2.9 std::alloc源码剖析，7</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128130019900.png" alt="image-20211128130019900"></p>
<ul>
<li>G4.9 中<code>start_free</code>是通过<code>operator new</code>进行分配的，所以可以重载<code>operator new</code>接管内存分配，而G2.9中的<code>malloc</code>是不可以进行重载的；</li>
</ul>
<h3 id="g29-stdalloc源码剖析8"><a class="markdownIt-Anchor" href="#g29-stdalloc源码剖析8"></a> G2.9 std::alloc源码剖析，8</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128130031869.png" alt="image-20211128130031869"></p>
<h3 id="g29-stdalloc源码剖析9"><a class="markdownIt-Anchor" href="#g29-stdalloc源码剖析9"></a> G2.9 std::alloc源码剖析，9</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128182301209.png" alt="image-20211128182301209"></p>
<h3 id="g29-stdalloc观念大整理"><a class="markdownIt-Anchor" href="#g29-stdalloc观念大整理"></a> G2.9 std::alloc观念大整理</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128182529355.png" alt="image-20211128182529355"></p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">c.<span class="built_in">push_back</span>(<span class="built_in">Foo</span>(<span class="number">1</span>)); <span class="comment">//执行完这行，临时对象就是消失了</span></span><br></pre></td></tr></table></figure>
<p>此处的<code>Foo(1)</code> 是个临时对象，非动态分配的，存在于<code>stack</code>，容器<code>c</code>的内存是通过<code>std::alloc</code>分配的，所以不带cookie;</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Foo* p = <span class="keyword">new</span> <span class="built_in">Foo</span>(<span class="number">2</span>); </span><br><span class="line">c.<span class="built_in">push_back</span>(*p);</span><br></pre></td></tr></table></figure>
<ul>
<li>
<p>此处的对象是在<code>heap</code>上建立的，<code>new</code>底层就是通过<code>malloc</code>进行内存分配的，所以分配的内存块是带cookie的（客户端不知道是否带cookie）；</p>
</li>
<li>
<p><code>c.push_back(*p);</code> 容器向分配器发出请求，申请内存，分配器给容器分配它所需要的内存块大小用于存储分配的<code>Foo</code>对象，这个内存块是不带cookie的；</p>
</li>
</ul>
<h3 id="g29-stdalloc批斗大会"><a class="markdownIt-Anchor" href="#g29-stdalloc批斗大会"></a> G2.9 std::alloc批斗大会</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128182616941.png" alt="image-20211128182616941"></p>
<ul>
<li>说明：</li>
</ul>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">obj* <span class="keyword">volatile</span> *my_free_list, *p; <span class="comment">//定义的是obj** my_free_list和obj* p这两个变量</span></span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="number">0</span> == start_free) <span class="comment">//推荐这种写法，因为如果不小心写成=号，编译器会出错，而如果写成start_free = 0，则是会编译通过的，这种Bug找起来就很困难了</span></span><br></pre></td></tr></table></figure>
<ul>
<li>变量尽量在使用的附近定义，否则中间做了很多其他操作，在使用的时候是不知道的；</li>
<li>当要申请一大块内存而系统内存不够时，不进行减半的尝试，因为在多进程的机器上可能会导致大灾难，这个大灾难是针对的其它的进程；</li>
<li><code>deallocate()</code>没有调用<code>free()</code> 或<code>delete</code>，源于其设计上的先天缺陷：交给客户的内存块没有指针一直记录着其地址，所以归还的时候不知道地址，就无法回收；</li>
</ul>
<h2 id="25-g49-pool-allocator运行观察"><a class="markdownIt-Anchor" href="#25-g49-pool-allocator运行观察"></a> 2.5 G4.9 pool allocator运行观察</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128205532576.png" alt="image-20211128205532576"></p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128205545429.png" alt="image-20211128205545429"></p>
<ul>
<li><code>list&lt;double&gt; 1st;</code> 默认使用的是标准分配器，底层使用<code>malloc</code>进行分配，分配的每个元素的内存都是带cookie的；</li>
<li><code>double</code>占8个字节，而list本身也带两个指针，所以一个元素的大小是16字节；</li>
<li>使用标准分配器的时候，总共进行了1000000次<code>malloc</code>分配，每次分配都带着cookie；而使用<code>__pool_alloc</code>只进行了 122 次<code>malloc</code>分配，每次分配也带着cookie；</li>
<li>不能观察到<code>malloc</code>真正分配出去的总量（含所有overhead），因为<code>malloc</code>不能重载，除非你有很高的技巧，清楚地理解了<code>malloc</code>的行为模式，理解了它管理的每个区块其实是个链表，链表有个头，知道了链表的头，遍历一遍，就能得到内存块的大小；</li>
</ul>
<h2 id="26-g29-stdalloc移植至c"><a class="markdownIt-Anchor" href="#26-g29-stdalloc移植至c"></a> 2.6 G2.9 std::alloc移植至C</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211128205618548.png" alt="image-20211128205618548"></p>
<h1 id="3-第三讲-mallocfree"><a class="markdownIt-Anchor" href="#3-第三讲-mallocfree"></a> 3. 第三讲 malloc/free</h1>
<blockquote>
<p>胸中自有丘壑</p>
<p>触类旁通</p>
</blockquote>
<h2 id="31-vc6和vc10的malloc比较"><a class="markdownIt-Anchor" href="#31-vc6和vc10的malloc比较"></a> 3.1 VC6和VC10的malloc比较</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129142928374.png" alt="image-20211129142928374"></p>
<ul>
<li>左边的图就是core stack，调用栈；</li>
<li><code>CRT</code>: C run time，即C的标准库；</li>
<li><code>heap_alloc_base</code>函数进行了小区块的阈值判断，小于等于1016使用<code>__sbh_alloc_block</code>函数进行内存分配，否则使用系统函数<code>HeapAlloc</code>进行内存分配；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129142941645.png" alt="image-20211129142941645"></p>
<ul>
<li>划掉的是VC10中不存在的部分；</li>
<li><code>heap_alloc_base</code>函数没有对小区块的阈值判断了，而是统一使用系统函数<code>HeapAlloc</code>进行内存分配；</li>
<li>VC10中没有SBH相关的操作了；</li>
</ul>
<h2 id="32-sbh之始-_heap_init和__sbh_heap_init"><a class="markdownIt-Anchor" href="#32-sbh之始-_heap_init和__sbh_heap_init"></a> 3.2 SBH之始— _heap_init()和__sbh_heap_init()</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129154151108.png" alt="image-20211129154151108"></p>
<ul>
<li>调用的是win32的API；</li>
<li>初始化一大块向CRT要的Heap；</li>
<li>分配了 16 个头，即HEADER：</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129154201493.png" alt="image-20211129154201493"></p>
<ul>
<li><code>pHeadData</code>指向内存；</li>
<li><code>pRegion</code>指向管理中心；</li>
</ul>
<h2 id="33-vc6内存分配"><a class="markdownIt-Anchor" href="#33-vc6内存分配"></a> 3.3 VC6内存分配</h2>
<h3 id="ioinit函数"><a class="markdownIt-Anchor" href="#ioinit函数"></a> ioinit函数</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194606600.png" alt="image-20211129194606600"></p>
<ul>
<li><code>ioinit</code>函数发出了第一次内存分配请求；</li>
<li><code>heap_init</code>只是分配 16 个头，头里面（即HEADER) 是什么东西是不清楚的；</li>
<li>注意此处的申请<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>32</mn><mo>∗</mo><mn>8</mn><mo>=</mo><mn>256</mn><mi>B</mi><mi>y</mi><mi>t</mi><mi>e</mi><mi>s</mi></mrow><annotation encoding="application/x-tex">32 * 8 = 256Bytes</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">8</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord">2</span><span class="mord">5</span><span class="mord">6</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord mathdefault" style="margin-right:0.03588em;">y</span><span class="mord mathdefault">t</span><span class="mord mathdefault">e</span><span class="mord mathdefault">s</span></span></span></span> 大小的内存；</li>
</ul>
<h3 id="_heap_alloc_dbg函数"><a class="markdownIt-Anchor" href="#_heap_alloc_dbg函数"></a> _heap_alloc_dbg函数</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194621587.png" alt="image-20211129194621587"></p>
<ul>
<li>Debug模式下，<code>heap_alloc_dbg</code>函数是在调整内存块的大小，此处的<code>nSize</code> 就是上面提到的 256Bytes;</li>
<li>也即是说，在Debug模式下，你需要的大小会被调整得更大一些（如右侧的图所示）；</li>
<li>此时还没分配，只是在调整（扩大空间），调整好之后分配就要分配这些东西；</li>
<li><code>_CrtMemBlockHeader</code>结构体变量说明：
<ul>
<li><code>szFileName</code>：记录是文件的哪一行发出来的申请；</li>
<li><code>nDataSize</code>: 对象实际的大小；</li>
<li><code>1Request</code>:  流水号；</li>
</ul>
</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194632047.png" alt="image-20211129194632047"></p>
<ul>
<li><code>heap_alloc_dbg</code>函数此时是在调整指针；</li>
<li><mark>所有经过<code>malloc</code>分配的内存块都用链表串起来了</mark>，即使这块内存块已经给用户了，仍然在它(sbh)的掌控之中，这是在调试模式下；</li>
<li>之所以在调试器能追踪内存，因为在调试模式下，多了很多东西，反映到图上就是多了深灰色之外的东西；</li>
<li>此处调用了<code>memset</code>给特定位置设置初值，以便观察后续的内存块变化情况；</li>
</ul>
<h3 id="_heap_alloc_base函数"><a class="markdownIt-Anchor" href="#_heap_alloc_base函数"></a> _heap_alloc_base函数</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194650512.png" alt="image-20211129194650512"></p>
<ul>
<li>此处的<code>size</code>是经过扩充调整后的大小，将这个大小与阈值进行比较；</li>
<li>这个<code>size</code>目前还没加cookie（8bytes），如果加上cookie后这个size小于1024，它就是小区块，而现在还没加cookie，所以此处是小于 1016；</li>
</ul>
<h3 id="__sbh_alloc_block函数"><a class="markdownIt-Anchor" href="#__sbh_alloc_block函数"></a> __sbh_alloc_block函数</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194739329.png" alt="image-20211129194739329"></p>
<ul>
<li><code>intSize</code> 就是之前得到的内存块大小；</li>
<li><code>2 * sizeof(int)</code>就是加 2 个cookie；</li>
<li>最后的部分是在做<code>RoundUp</code>，调整到 16 的倍数；</li>
<li>也就是说通过<code>malloc</code>分配的内存的实际大小，也是真正消耗掉的内存大小，是：要分配的大小经过调整补充（32bytes，给调试器使用的）再加上cookie，最后调整为16的倍数；</li>
<li>图中cookie记录的值是实际内存大小（图中一整块的大小），本来是0x130，但是记录的却是0x131，结尾的 1 表示这块内存已经被占用了，一旦被sbh回收，就会变成 0x130；</li>
<li>从<code>ioinit</code>-&gt;<code>_malloc_dbg</code>-&gt;<code>_nh_malloc_dbg</code>-&gt;<code>_heap_alloc_dbg</code>-&gt;<code>_heap_alloc_base</code>-&gt;<code>__sbh_alloc_block</code>都是在计算内存的大小，还没真正进行内存分配，图中的那些值都还没设置；</li>
</ul>
<h3 id="__sbh_alloc_new_region函数"><a class="markdownIt-Anchor" href="#__sbh_alloc_new_region函数"></a> __sbh_alloc_new_region函数</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194803230.png" alt="image-20211129194803230"></p>
<ul>
<li>此处真正进行内存分配；</li>
<li>1个HEADER负责管理1MB，通过管理中心进行管理；</li>
<li>通过<code>LISTHEAD</code>知道，每个GROUP一共有64条双向链表；</li>
<li>总结：1个HEADER将会申请真正的内存1MB，将来要分割出去的时候就从这块内存中进行分割；为了对这块内存切割后的内存块进行管理，又建立了<code>REGION</code>；<code>REGION</code>的大小是16k；</li>
</ul>
<h3 id="__sbh_alloc_new_group函数"><a class="markdownIt-Anchor" href="#__sbh_alloc_new_group函数"></a> __sbh_alloc_new_group函数</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194816585.png" alt="image-20211129194816585"></p>
<ul>
<li>从<code>HEADER</code>指向的内存从中分割内存块；</li>
<li>32个Group逻辑上对应HEADER指向的内存（虚拟空间），将该内存切分为32个单元，每个单元就是32k；每个单元又细分为8个page，每个page的大小为4k（计算机中通常将4k称为1个page）；<code>sbh</code>设置一些指针，将这些page串起来；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194841648.png" alt="image-20211129194841648"></p>
<ul>
<li>这8个<code>page</code>在内存中是连续的；</li>
<li>64条链表，管理的最大的区块是1k，那么每条链表负责的任务是什么呢？  类比于GNU编译器，每条链表负责的是8的倍数的内存大小，这里的最后一条链表负责 1kB，通过计算可得第一条链表负责 16B，第二条链表负责 32B，…；</li>
<li>当切割的内存块的大小大于1k的时候，就归最后一条链表管理，小于1k的时候就计算应该归哪条链表管理；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194901578.png" alt="image-20211129194901578"></p>
<ul>
<li>这就是从<code>page</code>中切割内存块的操作；</li>
<li>图中 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>0</mn><mi>x</mi><mn>130</mn></mrow><annotation encoding="application/x-tex">0x130</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span><span class="mord mathdefault">x</span><span class="mord">1</span><span class="mord">3</span><span class="mord">0</span></span></span></span> 的就是切割出去的，红色的地址 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>007</mn><mi>d</mi><mn>0</mn><mi>f</mi><mi>f</mi><mn>8</mn></mrow><annotation encoding="application/x-tex">007d0ff8</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord">0</span><span class="mord">0</span><span class="mord">7</span><span class="mord mathdefault">d</span><span class="mord">0</span><span class="mord mathdefault" style="margin-right:0.10764em;">f</span><span class="mord mathdefault" style="margin-right:0.10764em;">f</span><span class="mord">8</span></span></span></span> 是传出去的地址，但是这是在debug模式下，所以这个地址还会继续调整，扣除debug header，只将真正需要的内存地址传出去，这才是使用者真正拿到的地址，这个长度(100h)就是当初使用者申请的大小，这里的使用者就是当初的<code>ioinit</code>；</li>
<li>这个page还剩 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>e</mi><mi>c</mi><mn>0</mn><mo>=</mo><mi>f</mi><mi>f</mi><mn>0</mn><mo>−</mo><mn>130</mn></mrow><annotation encoding="application/x-tex">ec0 = ff0 - 130</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord mathdefault">e</span><span class="mord mathdefault">c</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathdefault" style="margin-right:0.10764em;">f</span><span class="mord mathdefault" style="margin-right:0.10764em;">f</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord">3</span><span class="mord">0</span></span></span></span>，其中 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>f</mi><mi>f</mi><mn>0</mn></mrow><annotation encoding="application/x-tex">ff0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathdefault" style="margin-right:0.10764em;">f</span><span class="mord mathdefault" style="margin-right:0.10764em;">f</span><span class="mord">0</span></span></span></span> 就是4080；</li>
<li>切割只是cookie的调整；</li>
<li>展开的切割好的内存块中，前两个数据有错误，此处不是0了，而是对应的两个指针；第三个数据(<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>0042</mn><mi>e</mi><mi>e</mi><mn>08</mn></mrow><annotation encoding="application/x-tex">0042ee08</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span><span class="mord">0</span><span class="mord">4</span><span class="mord">2</span><span class="mord mathdefault">e</span><span class="mord mathdefault">e</span><span class="mord">0</span><span class="mord">8</span></span></span></span>)指向发出内存申请的文件名<code>ioinit.c</code>；第4个数据(<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>00000081</mn></mrow><annotation encoding="application/x-tex">00000081</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">8</span><span class="mord">1</span></span></span></span>)是文件的哪一行发出的内存申请；第5个数据(<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>0000100</mn></mrow><annotation encoding="application/x-tex">0000100</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">1</span><span class="mord">0</span><span class="mord">0</span></span></span></span>) 表示使用者真正需要的数据大小；第6个数据(<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>00000002</mn></mrow><annotation encoding="application/x-tex">00000002</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span><span class="mord">2</span></span></span></span>)表示<code>_CRT_BLOCK</code>，表示这一块是给 CRT 用的；</li>
<li><code>main</code>执行结束后，可能还有区块，这并不一定是内存泄漏，因为这可能是CRT在使用，查看<code>nBlockUse</code>变量是否为<code>_CRT_BLOCK</code>，那么这就是合理的；</li>
<li>在<code>main</code>结束之前的一刻，发现有<code>_NORMAL_BLOCK</code> 的内存块，才说明存在内存泄漏；</li>
<li>像130h 这一个区块应该由第 304 / 16 - 1 = 18号链表供应；</li>
</ul>
<h2 id="34-sbh行为分析"><a class="markdownIt-Anchor" href="#34-sbh行为分析"></a> 3.4 SBH行为分析</h2>
<h3 id="分配"><a class="markdownIt-Anchor" href="#分配"></a> 分配</h3>
<h4 id="首次分配"><a class="markdownIt-Anchor" href="#首次分配"></a> 首次分配</h4>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194922520.png" alt="image-20211129194922520"></p>
<ol>
<li>
<p>需求：<code>ioinit.c</code>的 line#81 申请 100h，经过调整区块大小为130h；</p>
</li>
<li>
<p><code>sbh</code>面对这样的内存申请，在初始化的时候已经有16个HEADER，现在第0个HEADER，先通过<code>VirtualAlloc(0, 1Mb, MEM_RESERVE,...)</code>分配1Mb的空间（从操作系统海量的内存中获得的空间）；</p>
<ul>
<li>
<p>0：表示don’t care，不在意从什么地方分配的空间；</p>
</li>
<li>
<p>1Mb：表示需要的大小；</p>
</li>
<li>
<p><code>MEM_RESERVE</code>: 保留，保留这个地址空间，不需要真的有内存在这个地址；</p>
</li>
</ul>
</li>
<li>
<p>另一个指针通过<code>HeapAlloc</code> 函数从<code>_crtheap</code>中获取到一块大小为<code>sizeof(REGION)</code>的内存空间；<code>REGION</code>中包含的东西在之前已经看过其结构体了，其中还包含了32个Group，每个Group包含64对指针；</p>
</li>
<li>
<p>从1Mb中通过<code>VirtualAlloc(addr, 32Kb, MEM_COMMIT)</code>真正地划分出32K的内存（此处的<code>MEM_COMMIT</code>表示真的给我，可以想象1Mb的空间里除了32K有内存,其它的都是空的、虚的，没有内存，只有号码），1Mb空间中划分出了32个32K，对应于32个Group；将32K切成更小的单元即8个page，放大了看就是上图中最下面的8个page，这8个page各有两个指针，通过指针将这些page串起来，最后串回到64个链表的最后一个（之所以串回到最后一个链表，是因为每个page的大小为4080，大于1k；64条链表分别管理的区块大小为16B、32B、48B、…，而最后一个链表管理所有1k以上的区块，而目前这些page都是1k以上的，所以全部都归第64条链表管理）；</p>
</li>
<li>
<p>以上就是为了第一次分配准备的内存；</p>
</li>
<li>
<p>接下来开始切割，为了应付第一次的内存申请，8个page，从第一个page开始切，图中第二个大图就是page放大后的图，第一个图就是切割后给出去的130h大小的内存的具体内容，其中包含debug header以及无人区，而客户实际得到的地址是指向实际需要的大小100h的地址；在实际需要的内存大小100h的前后都有<code>fdfdfdfd</code>，当用户获得指向100h的地址后，会往下写，可能会写到后面的<code>fdfdfdfd</code>中，而在回收的时候，调试器会检测<code>fdfdfdfd</code>是否被修改，如果被修改了，就会发出警告⚠️，这就是无人区，有隐患存在，是绝对不可以被改的内容；</p>
</li>
<li>
<p>申请100h，调整后为130h，理应由Group0的#18 list供应，但是现在只有 #63 list链接着内存块，其他链表都是自己链接到自己（为空），当用户发出申请的时候，供应端会将自己的状况告诉用户端 ，REGION中的64bits变量，对应于64条链表，哪条链表有链接着区块，对应的bit就会被设置为1，否则为0；当前的情况只有最后一条链表挂着区块，所以只有最后一个bit是1，其他都是0；每一行bits变量表示一个Group，所以有32行bits变量；</p>
</li>
</ol>
<h4 id="第2次分配"><a class="markdownIt-Anchor" href="#第2次分配"></a> 第2次分配</h4>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129194942115.png" alt="image-20211129194942115"></p>
<ol>
<li>某个申请x字节的内存，经过添加Debug header、cookie，以及调整为16的倍数后需要的内存大小为240h；通过计算得到应该由#35 list供应，接着就去检查Group0的64bit变量中的第35号对应的bit是0还是1，目前只有最后一个bit对应的值为1，其他都是0，也就是说应该供应的#35 list为空，只能退而求其次，找比较大的，目前只有最后一条链表，从之前的page1中剩余的内存中切割；</li>
<li>Group结构体中的cntEntries变量，当需要分配的时候+1，回收的时候-1；当值为0的时候，表示8个page可以全部收回来，还给操作系统；</li>
<li>图中Region区域的红色的0表示正在使用Group0；如果Group0的8个page都使用完后，就继续往下使用Group1，…；</li>
</ol>
<h4 id="第3次分配"><a class="markdownIt-Anchor" href="#第3次分配"></a> 第3次分配</h4>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195001985.png" alt="image-20211129195001985"></p>
<ol>
<li>申请的70h，在sbh先检查应该由第几号链表供应刚刚好，结果发现其对应的链表的bit是0，于是只好找最靠近的有区块链接的链表，找到了最后一个链表；</li>
<li>从最后一个链表中找到page1，从剩下的内存中划分70h；</li>
</ol>
<h4 id="第15次分配释放"><a class="markdownIt-Anchor" href="#第15次分配释放"></a> 第15次分配，释放</h4>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195014337.png" alt="image-20211129195014337"></p>
<ol>
<li>并不是每个应用程序都是在第15次，这里只是作为观察选取的一次；</li>
<li>14-&gt;13，释放，要先减一；</li>
<li>这次还的是第2次分配的 240h，调用<code>free</code>进行释放，归还到#35 list，挂到35号链表上；回收的方式就是<mark>将这块内存的cookie里的241修改成240，就表示进行了回收</mark>，相关的数字进行修改（可能会做）；</li>
<li>修改64bit变量中对应的第 36 个bit（表示35号链表）的数字为 1；（00000000 10000001，其中每一位表示4bit）；</li>
</ol>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195027869.png" alt="image-20211129195027869"></p>
<ol>
<li>需要分配b0h，应该由#10 list供应，但是检查bit位发现第11个bit值为0，就要往比较大的区块进行查找，#35 list有区块，所以应该由 #35 list供应，#35 list刚刚回收了240h的内存，所以从这块内存里切；</li>
<li>240h切出去b0h，还剩 190h，这个内存块变小了，就要进行移动，通过计算 <span class="katex"><span class="katex-mathml"><math><semantics><mrow><mn>190</mn><mi>h</mi><mi mathvariant="normal">/</mi><mn>10</mn><mi>h</mi><mo>−</mo><mn>1</mn><mo>=</mo><mn>24</mn></mrow><annotation encoding="application/x-tex">190h/10h - 1= 24</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mord">9</span><span class="mord">0</span><span class="mord mathdefault">h</span><span class="mord">/</span><span class="mord">1</span><span class="mord">0</span><span class="mord mathdefault">h</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord">4</span></span></span></span>，应该挂在 #24 list上，所以第 25 个bit应该从0 修改为 1；</li>
<li>这个过程就是第15次的时候刚刚回收了 240h 的内存，第16次分配的时候就要从刚刚回收的内存中进行切割，剩下的内存块（190h） 比较小，就进行移动，对应的bit也要进行调整；</li>
</ol>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195044199.png" alt="image-20211129195044199"></p>
<ol>
<li>第 n 次分配设计的是Group1的区块不足够，相对应的要划分一块32k的内存，将它划分为8个page，这是一个新的Group，之前的Group1中的32k的使用状态是 02000014 00000000，里面有3个链表挂了区块，有几块不知道；</li>
<li>第 n 次分配需要 230h的内存大小，之前 Group1上的链表挂的区块不能满足这个要求，于是新启动一个Group2（图中的数字变成了1），其他的操作都是一样的；</li>
</ol>
<h3 id="区块合并"><a class="markdownIt-Anchor" href="#区块合并"></a> 区块合并</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195137875.png" alt="image-20211129195137875"></p>
<p>如果回收的内存是相邻的，是不是应该合并呢？好的设计应该是要合并的。</p>
<p>图中空白的区块表示已经回收了的，阴影部分表示可以进行回收的区块。</p>
<p>目前图一中的待回收的内存块前后都是已经回收的300h大小的内存块，这两个内存块都落在#(300h/10h - 1) 这条链表上，要归还目前这个阴影内存块，就要去判断上面和下面是不是都是已经是回收的内存块，这就谈到为什么要有上下cookie。直观地想，cookie是记录整个内存块的大小，应该只需要一个就好了，为什么上下都有一个一模一样的cookie呢？</p>
<p>回收的步骤：</p>
<ol>
<li>先将待回收的内存块的cookie中的 1 修改为 0；</li>
<li>图中弓箭所在的地方的指针往上4个字节，知道了长度为300h，从这个地址开始加上300h到达了下一块内存的起点，即cookie，能够去检查最后一个bit，发现是0，所以这两块内存可以合并，得到了如图二所示的样子；</li>
<li>因为上下都有cookie，所以从图一的弓箭处的位置往上4个字节，再往上4个字节，就到达了上一个内存块的cookie，知道了上一个内存块的大小，且知道了最后一个bit是0，于是可以继续往上调 300h到达了上一个内存块的上cookie位置，将它们进行合并，就得到了图三的样子；</li>
<li>sbh 系统计算 900h 应该链到哪条链表上；</li>
</ol>
<p>所以，如果没有下cookie的设计，就无法管理上方区块的合并。</p>
<h3 id="freep"><a class="markdownIt-Anchor" href="#freep"></a> free(p)</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195156640.png" alt="image-20211129195156640"></p>
<p>首先要知道落在哪一个1Mb之中（一个Header对应一个1Mb的内存），在这1Mb中又要知道落在32段的哪一段之中，知道是哪一段就知道了对应于哪一个Group，然后才能去除以16再减一，确定链在哪个链表上。</p>
<p>指针p如何知道是哪个Header？最开始有 16 个Header，<code>__sbh_pHeaderList</code>指向这16个Header，每个Header的大小是固定的。回收的时候知道内存块的大小，通过p+内存块的大小，计算属于哪个Header，如果找不到，则说明当初不是从这里分配出去的，找到属于哪个Header后，将该指针减去这个1Mb的头指针再除以32k，计算得到位于1Mb的哪个段（如果从0算起，还要减1）；</p>
<p>p 花落谁家？</p>
<p>Q：落在哪个 Header 内？</p>
<p>A：每个Header都有指针指向1Mb的内存块，且这个内存块的大小也知道了，于是通过计算头+内存块大小，可以知道 p 是落在哪个Header内了。</p>
<p>Q：落在哪个 Group 内？</p>
<p>A：p 减去 1Mb的头指针，除以32k，就知道落在第几段，也就落在哪个Group内。</p>
<p>Q：落在哪个 free-list 内？（被哪个 free-list 链住？）</p>
<p>A：指针往上看就是cookie，通过cookie知道了内存块的大小，然后除以10h再减去1，就知道落在哪个链表；</p>
<h3 id="分段管理之妙"><a class="markdownIt-Anchor" href="#分段管理之妙"></a> 分段管理之妙</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195359755.png" alt="image-20211129195359755"></p>
<p>一段是32k，切成8大块。</p>
<ol>
<li>如何判断全回收？</li>
</ol>
<p>如果链表全部变成0就表示全部给出去了，那么如何判断全回收呢？Group中有<code>cntEntries</code>变量，只要这个值变成0，就表示全回收。</p>
<ol start="2">
<li>不要躁进！</li>
</ol>
<p>全回收的时候回到了初始的状态（首次分配），8个page不能再进行合并，因为并不急着还给os，方便下一次的分配，等到下一次全回收才会归还给os。只有手上有两个全回收的时候才会归还给系统。</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195444734.png" alt="image-20211129195444734"></p>
<p><code>defer</code>是延缓的意思，通过<code>defer</code>来完成<mark>不要躁进</mark>的目标。图中已经说明了Defer。</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195457085.png" alt="image-20211129195457085"></p>
<p>恢复到初始状态。图中的8个page是不会合并的。</p>
<h2 id="35-vc6heap-state-reporting-functions"><a class="markdownIt-Anchor" href="#35-vc6heap-state-reporting-functions"></a> 3.5 VC6,Heap State Reporting Functions</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195538405.png" alt="image-20211129195538405"></p>
<p>调试模式下才有Debug Header，才可以去追踪，图中的函数就是可以利用的。</p>
<h2 id="36-vc-malloc-gcc-allocator"><a class="markdownIt-Anchor" href="#36-vc-malloc-gcc-allocator"></a> 3.6 VC malloc + GCC allocator</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195616271.png" alt="image-20211129195616271"></p>
<p>GCC的allocator的原理和VC 的 malloc 是相似的，allocator中有16条链表，管理的区块最高到128B，每次需要的时候向malloc要内存，allocator中的16条链表的设计不是为了速度快，因为malloc已经很快了，目的是为了<mark>去除cookie</mark>。</p>
<h2 id="37-叠床架屋有必要吗"><a class="markdownIt-Anchor" href="#37-叠床架屋有必要吗"></a> 3.7 叠床架屋，有必要吗？</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211129195649805.png" alt="image-20211129195649805"></p>
<p><mark>浪费，但是有必要。</mark></p>
<p>CRT(malloc/free) 是 C 的层次，是跨平台的，并不依附于哪个操作系统，所以它并不能预设下面的操作系统有没有做内存管理，同样的道理，C++ Library(std::allocator) 最终要调用到 CRT(malloc/free)，它也不能去预设 malloc 有没有做内存管理，因为它是C++的标准库，不能依赖于底层C的东西。</p>
<p>每个层次都不敢去依赖下面，所以自己来做内存管理。</p>
<h1 id="4-第四讲-lokiallocator"><a class="markdownIt-Anchor" href="#4-第四讲-lokiallocator"></a> 4. 第四讲 loki::allocator</h1>
<blockquote>
<p>成竹在胸</p>
</blockquote>
<h2 id="41-上中下三个classes分析"><a class="markdownIt-Anchor" href="#41-上中下三个classes分析"></a> 4.1 上中下三个classes分析</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208161947132.png" alt="image-20211208161947132"></p>
<p>Loki Library是一个在业界很前沿的库，但是不成熟，作者对这个库的维护只到0.1.7版本。</p>
<p>之前讲过GNU C的编译器不会将内存归还给OS，在多进程的时候会有影响。但是loki会将内存进行归还。</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162000111.png" alt="image-20211208162000111"></p>
<p>三个class，从下往上就是从底层到上层。</p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162011380.png" alt="image-20211208162011380"></p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162022485.png" alt="image-20211208162022485"></p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162031365.png" alt="image-20211208162031365"></p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162045656.png" alt="image-20211208162045656"></p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162055418.png" alt="image-20211208162055418"></p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162108361.png" alt="image-20211208162108361"></p>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162120097.png" alt="image-20211208162120097"></p>
<h2 id="42-loki-allocator行为图解"><a class="markdownIt-Anchor" href="#42-loki-allocator行为图解"></a> 4.2 loki allocator行为图解</h2>
<h3 id="chunk"><a class="markdownIt-Anchor" href="#chunk"></a> Chunk</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162131822.png" alt="loki allocator，Chunk"></p>
<h3 id="chunkallocate"><a class="markdownIt-Anchor" href="#chunkallocate"></a> Chunk::Allocate()</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162141865.png" alt="Chunk::Allocate()"></p>
<p>数组代替链表，索引代替指针。</p>
<h3 id="chunkdeallocate"><a class="markdownIt-Anchor" href="#chunkdeallocate"></a> Chunk::Deallocate()</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162154856.png" alt="image-20211208162154856"></p>
<h3 id="fixedallocatorallocate"><a class="markdownIt-Anchor" href="#fixedallocatorallocate"></a> FixedAllocator::Allocate()</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162205575.png" alt="image-20211208162205575"></p>
<p>其中#line 20中的<code>allocChunk = &amp;*i;</code>，<code>*i</code>得到Chunk，<code>&amp;*i</code>得到了Chunk的首地址；</p>
<p>此处的分配动作中之所以有<code>deallocChunk = &amp;chunks_.front()</code>是因为往vector中添加新的Chunk的时候可能会出现数据的移动，如果出现了数据移动，那之前的iterator就会失效，所以对这些值进行重新设定。</p>
<p>逻辑整理：假设现在有1w个Chunk，有人来申请，先找出被标识的区块，否则从头找起哪个Chunk有区块，否则创建新的Chunk。</p>
<h3 id="fixedallocatorvicinityfind"><a class="markdownIt-Anchor" href="#fixedallocatorvicinityfind"></a> FixedAllocator::VicinityFind()</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162223294.png" alt="image-20211208162223294"></p>
<p>VicinityFind()：临近查找。夹杀法找到地址。</p>
<h3 id="fixedallocatordodeallocate"><a class="markdownIt-Anchor" href="#fixedallocatordodeallocate"></a> FixedAllocator::DoDeallocate()</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162233529.png" alt="image-20211208162233529"></p>
<h3 id="loki-allocator检讨"><a class="markdownIt-Anchor" href="#loki-allocator检讨"></a> Loki allocator检讨</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208162243742.png" alt="image-20211208162243742"></p>
<p>loki 中使用了 vector，而 vector 使用的是标准库的分配器，容器使用 loki 的时候已经和标准库的分配器脱离了关系，所以不存在鸡生蛋和蛋生鸡的问题。所以当你使用loki的时候，其实已经涉及到了标准库的分配器和容器以及loki。</p>
<p>可以自己实现 vector，替代loki中的vector，那么就不会有上面这种问题了。</p>
<h1 id="5-第五讲-other-issues"><a class="markdownIt-Anchor" href="#5-第五讲-other-issues"></a> 5. 第五讲 other issues</h1>
<h2 id="51-gnu-c"><a class="markdownIt-Anchor" href="#51-gnu-c"></a> 5.1 GNU C++</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208181929620.png" alt="image-20211208181929620"></p>
<h2 id="52-gnu-c对allocators的描述"><a class="markdownIt-Anchor" href="#52-gnu-c对allocators的描述"></a> 5.2 GNU C++对allocators的描述</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208181942134.png" alt="image-20211208181942134"></p>
<ul>
<li>
<p>之所以谈到容器，因为分配器就是为容器服务的。</p>
</li>
<li>
<p><code>::operator new</code>继续往下调用的是<code>malloc</code>。</p>
</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208181954504.png" alt="image-20211208181954504"></p>
<ul>
<li><code>__gnu_cxx::new_allocator</code>和<code>__gnu_cxx::malloc_allocator</code>没有什么特殊的设计，没有内存池的设计，这就是最容易满足需求的做法。</li>
<li><code>__gnu_cxx::new_allocator</code>相对来说稍微好一些，因为<code>::operator new</code>可重载。</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182007740.png" alt="image-20211208182007740"></p>
<ul>
<li><code>fixed-size pooling cache</code>固定大小的内存池缓存，就是第二讲中提到的16条链表，每条管理不同大小的内存块，内存块都是8的倍数；</li>
<li><code>cache</code>就是之前提到的先准备一大块内存，然后慢慢划分，最大的优势是<mark>去除cookie</mark>，同时因为减少了<code>malloc</code> 的调用，速度上有一些提升，但这不应该是最大的优势；</li>
<li><code>__gnu_cxx::__mt_alloc</code>是多线程的allocator。</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182018073.png" alt="image-20211208182018073"></p>
<ul>
<li>注意测试分配器的三个指标；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182028440.png" alt="image-20211208182028440"></p>
<ul>
<li>C++的数组，是静态的，不是动态的，因此避免了&quot;在运行期添乱、增加开销&quot;；</li>
<li>&quot;甚至在program startup 情况下也可使用&quot;的意思是在进入程序员编写的程序<code>main</code>之前（右侧的core dump）就可以使用<code>__gun_cxx::array_allocator</code>了，也就是说还没有准备好动态分配的时候，就已经有<code>__gun_cxx::array_allocator</code>了。不过在VC6下的startup被写成了一个函数<code>mainCRTStartup()</code>，这个函数里的第一个动作就是<code>_heap_init</code>进行内存管理的初始化，除非是在这个动作之前还要做事情，否则&quot;设置在program startup 情况下也可使用&quot;这句话的意义就不大了，因为内存管理的初始化完成后，其他的分配器也可以使用了；</li>
</ul>
<h2 id="53-vs2013-span-stylecolorblue标准span分配器与span-stylecolorpurplenew_allocatorspan"><a class="markdownIt-Anchor" href="#53-vs2013-span-stylecolorblue标准span分配器与span-stylecolorpurplenew_allocatorspan"></a> 5.3 VS2013 <span style="color:blue">标准</span>分配器与<span style="color:purple">new_allocator</span></h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182154525.png" alt="image-20211208182154525"></p>
<ul>
<li>没有做什么额外操作的分配器。</li>
</ul>
<h2 id="54-g49-span-stylecolorblue标准span分配器与span-stylecolorpurplenew_allocatorspan"><a class="markdownIt-Anchor" href="#54-g49-span-stylecolorblue标准span分配器与span-stylecolorpurplenew_allocatorspan"></a> 5.4 G4.9 <span style="color:blue">标准</span>分配器与<span style="color:purple">new_allocator</span></h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182206754.png" alt="image-20211208182206754"></p>
<ul>
<li>标准库中的默认分配器，没有做什么额外操作的分配器。</li>
</ul>
<h2 id="55-g49-malloc_allocator"><a class="markdownIt-Anchor" href="#55-g49-malloc_allocator"></a> 5.5 G4.9 malloc_allocator</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182235773.png" alt="image-20211208182235773"></p>
<h2 id="56-g49-array_allocator"><a class="markdownIt-Anchor" href="#56-g49-array_allocator"></a> 5.6 G4.9  array_allocator</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182258980.png" alt="image-20211208182258980"></p>
<ul>
<li>第二模板参数不管是使用<code>std::tr1::array</code> 还是<code>std::array</code>都一样，因为本质相同，底部是一个C++的数组；</li>
<li>C++的数组是静态的，不需要释放，不需要归还，所以<code>array_allocator</code>里面只有<code>allocate()</code> 函数，如果调用<code>deallocate()</code>则是调用的父类的接口，但是这个接口里面do nothing；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182323656.png" alt="image-20211208182323656"></p>
<ul>
<li><code>array_allocator&lt;int, array&lt;int, 65536&gt;&gt; myalloc(&amp;my);</code> 调用构造函数，其中<code>myalloc</code>是对象名称；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182311808.png" alt="image-20211208182311808"></p>
<p>其中</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> ARRAY std::array&lt;<span class="keyword">int</span>, 65536&gt;;</span><br><span class="line">ARRAY* pa = <span class="keyword">new</span> ARRAY;</span><br></pre></td></tr></table></figure>
<p>这两行代码等同于上一个图中的<code>int my[65536];</code> 区别在于，<code>int my[65536];</code> 是静态数组，而这两行是使用动态分配的方式分配的内存；</p>
<h2 id="57-g49-debug_allocator"><a class="markdownIt-Anchor" href="#57-g49-debug_allocator"></a> 5.7 G4.9 debug_allocator</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182345728.png" alt="image-20211208182345728"></p>
<ul>
<li><code>sizeof(size_type)</code>在绝大多数系统中都是4，记录区块的大小；</li>
<li><code>_S_extra()</code>函数的结果表示额外的内存相当于几个元素；</li>
<li>包裹另一个分配器，让分配的区块还多带extra的空间，用于记录整个区块的大小，扮演的角色类似于cookie；</li>
<li>做内存管理的时候，“阳春”型（什么都没做）是没有用的，真正有用的是设计成内存池，设计成内存池的主要用意是去cookie，也提升了一些效率（减少了malloc的调用次数），去除了cookie，又调用debug_allocator，又包装了一层，这样的意义不大；</li>
</ul>
<h2 id="58-g29容器使用的分配器不是-stdallocator-而是-stdalloc"><a class="markdownIt-Anchor" href="#58-g29容器使用的分配器不是-stdallocator-而是-stdalloc"></a> 5.8 G2.9容器使用的分配器不是 std::allocator 而是 std::alloc</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182424167.png" alt="image-20211208182424167"></p>
<ul>
<li>容器使用的分配器都是<code>std::alloc</code>;</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182434533.png" alt="image-20211208182434533"></p>
<ul>
<li>特点：只拿内存却不还，不会影响自己，但是可能会影响其他进程；</li>
</ul>
<h2 id="59-g49-__pool_alloc-用例"><a class="markdownIt-Anchor" href="#59-g49-__pool_alloc-用例"></a> 5.9 G4.9 __pool_alloc 用例</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182506249.png" alt="image-20211208182506249"></p>
<p>真正有用的分配器是这种<strong>智能</strong>型的分配器，我们追求的是没有cookie。</p>
<h2 id="510-g49-bitmap_allocator"><a class="markdownIt-Anchor" href="#510-g49-bitmap_allocator"></a> 5.10 G4.9 bitmap_allocator</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182532557.png" alt="image-20211208182532557"></p>
<ul>
<li>容器一次都会只要一个元素；</li>
</ul>
<h3 id="5101-关于blockssuper-blocksbitmapmini-vector"><a class="markdownIt-Anchor" href="#5101-关于blockssuper-blocksbitmapmini-vector"></a> 5.10.1 关于blocks，super-blocks，bitmap，mini-vector</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182746006.png" alt="image-20211208182746006"></p>
<ul>
<li>blocks就是客户需要的；</li>
<li>一次性申请 64个blocks 用来后续的供应；</li>
<li>64个blocks + bitmap + use count = super-blocks；</li>
<li>bitmap记录了blocks的使用情况，一个bit位表示1个block，1 表示在手中，0表示给出去，当前的状态是全部都在手中；</li>
<li><code>use count</code>表示使用了几个block，目前的状态是0个被使用；</li>
<li>block size 是 8 的倍数，8，16，24… 这样的增长，只允许这样的大小，图中假设每个block的size是8，所以super block size = 524 bytes；</li>
<li><code>__mini_vector</code>中的一个元素表示一个super blocks；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182812810.png" alt="image-20211208182812810"></p>
<ul>
<li>使用了第1个block；</li>
<li>bitmap的变化次序和blocks的变化次序相反，blocks从左往右，bitmap从右往左；</li>
<li>bitmap的最后一个bit变成0；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182833634.png" alt="image-20211208182833634"></p>
<ul>
<li>分配了第二个block；</li>
<li>bitmap的倒数第二个bit变成0；</li>
<li>use count变成2；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182851410.png" alt="image-20211208182851410"></p>
<ul>
<li>使用了63个blocks；</li>
<li>只有最后一个block没有使用，所以对应bitmap的第一位为1，其他都为0；</li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182654014.png" alt="image-20211208182654014"></p>
<ul>
<li>将倒数第三个block归还；</li>
<li>use count变成62；</li>
<li>相对应的bit为变成1010；</li>
</ul>
<h3 id="5102-1st-super-block用罄启动-2nd-super-block"><a class="markdownIt-Anchor" href="#5102-1st-super-block用罄启动-2nd-super-block"></a> 5.10.2 1st super-block用罄，启动 2nd super-block</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208182951952.png" alt="image-20211208182951952"></p>
<ul>
<li>第二个super-block一共有128个blocks，就需要128个bit，即4个整数（每个整数32位）；</li>
<li>第二个super-bloc的第1个block给出去了，所以bitmap[0]的最后1个bit变成了0；</li>
<li>标准库中的<code>vector</code>当空间不够的时候会进行 2 倍的增长，此处的<code>_mini_vector</code>就是实现了一个和标准库中的<code>vector</code>相似功能的容器，这里出现了数据的搬动，<code>_M_start</code>此时的值和只有一个元素的时候的<code>_M_start</code>的值是不一样的；</li>
</ul>
<h3 id="5103-2nd-super-block用罄启动-3rd-super-block"><a class="markdownIt-Anchor" href="#5103-2nd-super-block用罄启动-3rd-super-block"></a> 5.10.3 2nd super-block用罄，启动 3rd super-block</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208183021501.png" alt="image-20211208183021501"></p>
<ul>
<li>第三个super-block一共有256个blocks，需要256bit来表示每个block被使用的状态，即 8 个整数；</li>
<li>此时<code>_mini_vector</code>需要有第三个单元来控制第三个super-block；</li>
<li>因为<code>_mini_vector</code>是成倍增长的，所以此时有4个单元，但是最后一个单元还没被使用；</li>
<li>每个super-block只为一种value type服务；</li>
<li>图中的蓝色格子，每两格表示一个 entry；</li>
</ul>
<h3 id="5104-1st-super-block-全回收"><a class="markdownIt-Anchor" href="#5104-1st-super-block-全回收"></a> 5.10.4 1st super-block 全回收</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211211132840121.png" alt="1st super-block全回收"></p>
<ul>
<li>回收的时候使用了另一个<code>_mini_vector</code>，叫做<code>_S_free_list</code>；</li>
<li>当前的super-block已经是256blocks，因为回收了1st super block，所以下次再分配的时候，分配规模为 128blocks；</li>
<li>回收的vector中只存放64个super-block，如果有第65个super-block回收了，就会归还给O.S；</li>
<li>回收了的super-block要将<code>_mini_vector</code>中的这个entry移除，后面的entry元素要往前推；</li>
</ul>
<h3 id="5105-2nd-super-block-全回收"><a class="markdownIt-Anchor" href="#5105-2nd-super-block-全回收"></a> 5.10.5 2nd super-block 全回收</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208183133120.png" alt="image-20211208183133120"></p>
<h3 id="5106-3rd-super-block-全回收"><a class="markdownIt-Anchor" href="#5106-3rd-super-block-全回收"></a> 5.10.6 3rd super-block 全回收</h3>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208183157443.png" alt="image-20211208183157443"></p>
<h2 id="511-使用g49-分配器"><a class="markdownIt-Anchor" href="#511-使用g49-分配器"></a> 5.11 使用G4.9 分配器</h2>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208183226717.png" alt="image-20211208183226717"></p>
<ul>
<li>最精巧的两个分配器：<code>__pool_alloc</code>和<code>bitmap_allocator</code></li>
</ul>
<p><img src="https://gitee.com/maureen-liu/typora-image/raw/master/typora-image/image-20211208183240789.png" alt="image-20211208183240789"></p>
<ul>
<li>这是测试程序，列举了每个分配器的使用方式。</li>
</ul>


      <div>
        
        <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;">-------------本文结束<i class="fa fa-paw"></i>感谢您的阅读-------------</div>
    
</div>


        
      </div>

    </div>

    
    
    
        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>Maureen
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="https://maureen-liu.gitee.io/p/e088fcc4.html" title="C++内存管理">https://maureen-liu.gitee.io/p/e088fcc4.html</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>


      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/%E4%BE%AF%E6%8D%B7/" rel="tag"># 侯捷</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/p/46598833.html" rel="prev" title="C++面向对象高级编程（part I)">
      <i class="fa fa-chevron-left"></i> C++面向对象高级编程（part I)
    </a></div>
      <div class="post-nav-item">
    <a href="/p/9725cb23.html" rel="next" title="C++设计模式">
      C++设计模式 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          
    <div class="comments" id="valine-comments"></div>

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>
        
      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#0-overview"><span class="nav-text"> 0. Overview</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#01-%E5%BA%94%E5%85%B7%E5%A4%87%E7%9A%84%E5%9F%BA%E7%A1%80"><span class="nav-text"> 0.1 应具备的基础</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#02-%E7%9B%AE%E6%A0%87"><span class="nav-text"> 0.2 目标</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#03-%E5%B7%A5%E5%85%B7"><span class="nav-text"> 0.3 工具</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#04-%E7%BD%91%E7%BB%9C%E8%B5%84%E6%BA%90"><span class="nav-text"> 0.4 网络资源</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#05-%E4%B9%A6%E7%B1%8D"><span class="nav-text"> 0.5 书籍</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#1-%E7%AC%AC%E4%B8%80%E8%AE%B2-primitives"><span class="nav-text"> 1. 第一讲 primitives</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#11-c-%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F"><span class="nav-text"> 1.1 C++ 应用程序</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#12-c-memory-primitives"><span class="nav-text"> 1.2 C++ memory primitives</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#13-%E5%9B%9B%E4%B8%AA%E5%B1%82%E9%9D%A2%E7%9A%84%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95"><span class="nav-text"> 1.3 四个层面的基本用法</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-new-expression"><span class="nav-text"> 1.4 new expression</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#15-delete-expression"><span class="nav-text"> 1.5 delete expression</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#16-ctor-dtor-%E7%9B%B4%E6%8E%A5%E8%B0%83%E7%94%A8"><span class="nav-text"> 1.6 Ctor &amp; Dtor 直接调用</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#17-array-new-array-delete"><span class="nav-text"> 1.7 array new, array delete</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#18-array-sizein-memory-block"><span class="nav-text"> 1.8 array size，in memory block</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#19-placement-new"><span class="nav-text"> 1.9 placement new</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#110-c%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E5%88%86%E9%85%8D%E5%86%85%E5%AD%98%E7%9A%84%E9%80%94%E5%BE%84"><span class="nav-text"> 1.10 C++应用程序，分配内存的途径</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#111-c%E5%AE%B9%E5%99%A8%E5%88%86%E9%85%8D%E5%86%85%E5%AD%98%E7%9A%84%E9%80%94%E5%BE%84"><span class="nav-text"> 1.11 C++容器，分配内存的途径</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#112-%E9%87%8D%E8%BD%BD"><span class="nav-text"> 1.12 重载</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1121-%E9%87%8D%E8%BD%BDoperator-newoperator-delete"><span class="nav-text"> 1.12.1 重载::operator new&#x2F;::operator delete</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1122-%E9%87%8D%E8%BD%BDoperator-newoperator-delete"><span class="nav-text"> 1.12.2 重载operator new&#x2F;operator delete</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1123-%E9%87%8D%E8%BD%BDoperator-newoperator-delete"><span class="nav-text"> 1.12.3 重载operator new[]&#x2F;operator delete[]</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1124-%E9%87%8D%E8%BD%BD%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 1.12.4 重载示例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1125-%E9%87%8D%E8%BD%BD-newdelete"><span class="nav-text"> 1.12.5 重载 new()&#x2F;delete()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1126-basic_string-%E4%BD%BF%E7%94%A8-newextra-%E6%89%A9%E5%85%85%E7%94%B3%E8%AF%B7%E9%87%8F"><span class="nav-text"> 1.12.6 basic_string 使用 new(extra) 扩充申请量</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#113-allocator"><span class="nav-text"> 1.13 allocator</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1131-per-class-allocator"><span class="nav-text"> 1.13.1 per-class allocator</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#11311-v1%E7%89%88%E6%9C%AC"><span class="nav-text"> 1.13.1.1 v1版本</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#11312-v2%E7%89%88%E6%9C%AC%E5%8A%A0%E4%B8%8A%E4%BA%86embedded-pointer"><span class="nav-text"> 1.13.1.2 v2版本：加上了embedded pointer</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1132-static-allocator"><span class="nav-text"> 1.13.2 static allocator</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#11321-static-allocator-%E7%A4%BA%E4%BE%8B%E4%B8%8E%E7%BB%93%E6%9E%9C"><span class="nav-text"> 1.13.2.1 static allocator 示例与结果</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#11322-marco-for-static-allocator"><span class="nav-text"> 1.13.2.2 marco for static allocator</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1133-global-allocatorwith-multiple-free-lists"><span class="nav-text"> 1.13.3 global allocator（with multiple free-lists)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1134-%E5%B0%8F%E7%BB%93"><span class="nav-text"> 1.13.4 小结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#114-new-handler"><span class="nav-text"> 1.14 new handler</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#115-defaultdelete"><span class="nav-text"> 1.15 &#x3D;default，&#x3D;delete</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#2-%E7%AC%AC%E4%BA%8C%E8%AE%B2-stdallocator"><span class="nav-text"> 2. 第二讲 std::allocator</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#21-vc6-malloc"><span class="nav-text"> 2.1 VC6 malloc()</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#22-%E4%B8%8D%E5%90%8C%E7%BC%96%E8%AF%91%E5%99%A8%E7%9A%84%E6%A0%87%E5%87%86%E5%88%86%E9%85%8D%E5%99%A8%E7%9A%84%E5%AE%9E%E7%8E%B0"><span class="nav-text"> 2.2 不同编译器的标准分配器的实现</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#221-vc6-%E6%A0%87%E5%87%86%E5%88%86%E9%85%8D%E5%99%A8%E4%B9%8B%E5%AE%9E%E7%8E%B0"><span class="nav-text"> 2.2.1 VC6 标准分配器之实现</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#222-bc5-%E6%A0%87%E5%87%86%E5%88%86%E9%85%8D%E5%99%A8%E4%B9%8B%E5%AE%9E%E7%8E%B0"><span class="nav-text"> 2.2.2 BC5 标准分配器之实现</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#223-g29-%E6%A0%87%E5%87%86%E5%88%86%E9%85%8D%E5%99%A8%E4%B9%8B%E5%AE%9E%E7%8E%B0"><span class="nav-text"> 2.2.3 G2.9 标准分配器之实现</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2231-stdallocator%E7%9A%84%E5%AE%9E%E7%8E%B0"><span class="nav-text"> 2.2.3.1 std::allocator的实现</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2232-g29-%E5%AE%B9%E5%99%A8%E4%BD%BF%E7%94%A8%E7%9A%84%E5%88%86%E9%85%8D%E5%99%A8%E4%B8%8D%E6%98%AF-stdspan-stylecolorpurpleallocatorspan-%E8%80%8C%E6%98%AF-stdspan-stylecolorpurpleallocspan"><span class="nav-text"> 2.2.3.2 G2.9 容器使用的分配器，不是 std::allocator 而是 std::alloc</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2232-g29-stdspan-stylecolorpurpleallocspan-vs-g49span-stylecolorpurple__pool_allocspan"><span class="nav-text"> 2.2.3.2 (G2.9) std::alloc vs. (G4.9)__pool_alloc</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#224-g49-%E6%A0%87%E5%87%86%E5%88%86%E9%85%8D%E5%99%A8%E4%B9%8B%E5%AE%9E%E7%8E%B0"><span class="nav-text"> 2.2.4 G4.9 标准分配器之实现</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2241-stdallocator%E7%9A%84%E5%AE%9E%E7%8E%B0"><span class="nav-text"> 2.2.4.1 std::allocator的实现</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2242-pool-allocator%E4%BD%BF%E7%94%A8%E7%A4%BA%E4%BE%8B"><span class="nav-text"> 2.2.4.2 pool allocator使用示例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#225-%E5%B0%8F%E7%BB%93"><span class="nav-text"> 2.2.5 小结</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#23-g29-stdalloc-%E8%BF%90%E8%A1%8C%E6%A8%A1%E5%BC%8F"><span class="nav-text"> 2.3 G2.9 std::alloc 运行模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#embedded-pointers"><span class="nav-text"> embedded pointers</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc-%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A501"><span class="nav-text"> G2.9 std::alloc 运行一瞥.01</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc-%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A502"><span class="nav-text"> G2.9 std::alloc 运行一瞥.02</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A503"><span class="nav-text"> G2.9 std::alloc运行一瞥.03</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A504"><span class="nav-text"> G2.9 std::alloc运行一瞥.04</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A505"><span class="nav-text"> G2.9 std::alloc运行一瞥.05</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A506"><span class="nav-text"> G2.9 std::alloc运行一瞥.06</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A507"><span class="nav-text"> G2.9 std::alloc运行一瞥.07</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A508"><span class="nav-text"> G2.9 std::alloc运行一瞥.08</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A509"><span class="nav-text"> G2.9 std::alloc运行一瞥.09</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A510"><span class="nav-text"> G2.9 std::alloc运行一瞥.10</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A511"><span class="nav-text"> G2.9 std::alloc运行一瞥.11</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A512"><span class="nav-text"> G2.9 std::alloc运行一瞥.12</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E8%BF%90%E8%A1%8C%E4%B8%80%E7%9E%A513"><span class="nav-text"> G2.9 std::alloc运行一瞥.13</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#24-g29-stdalloc-%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%90"><span class="nav-text"> 2.4 G2.9 std::alloc 源码剖析</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%901"><span class="nav-text"> G2.9 std::alloc源码剖析，1</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%902"><span class="nav-text"> G2.9 std::alloc源码剖析，2</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%903"><span class="nav-text"> G2.9 std::alloc源码剖析，3</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%904"><span class="nav-text"> G2.9 std::alloc源码剖析，4</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%905"><span class="nav-text"> G2.9 std::alloc源码剖析，5</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%906"><span class="nav-text"> G2.9 std::alloc源码剖析，6</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%907"><span class="nav-text"> G2.9 std::alloc源码剖析，7</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%908"><span class="nav-text"> G2.9 std::alloc源码剖析，8</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%909"><span class="nav-text"> G2.9 std::alloc源码剖析，9</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E8%A7%82%E5%BF%B5%E5%A4%A7%E6%95%B4%E7%90%86"><span class="nav-text"> G2.9 std::alloc观念大整理</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#g29-stdalloc%E6%89%B9%E6%96%97%E5%A4%A7%E4%BC%9A"><span class="nav-text"> G2.9 std::alloc批斗大会</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#25-g49-pool-allocator%E8%BF%90%E8%A1%8C%E8%A7%82%E5%AF%9F"><span class="nav-text"> 2.5 G4.9 pool allocator运行观察</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#26-g29-stdalloc%E7%A7%BB%E6%A4%8D%E8%87%B3c"><span class="nav-text"> 2.6 G2.9 std::alloc移植至C</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#3-%E7%AC%AC%E4%B8%89%E8%AE%B2-mallocfree"><span class="nav-text"> 3. 第三讲 malloc&#x2F;free</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#31-vc6%E5%92%8Cvc10%E7%9A%84malloc%E6%AF%94%E8%BE%83"><span class="nav-text"> 3.1 VC6和VC10的malloc比较</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#32-sbh%E4%B9%8B%E5%A7%8B-_heap_init%E5%92%8C__sbh_heap_init"><span class="nav-text"> 3.2 SBH之始— _heap_init()和__sbh_heap_init()</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#33-vc6%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D"><span class="nav-text"> 3.3 VC6内存分配</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#ioinit%E5%87%BD%E6%95%B0"><span class="nav-text"> ioinit函数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#_heap_alloc_dbg%E5%87%BD%E6%95%B0"><span class="nav-text"> _heap_alloc_dbg函数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#_heap_alloc_base%E5%87%BD%E6%95%B0"><span class="nav-text"> _heap_alloc_base函数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#__sbh_alloc_block%E5%87%BD%E6%95%B0"><span class="nav-text"> __sbh_alloc_block函数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#__sbh_alloc_new_region%E5%87%BD%E6%95%B0"><span class="nav-text"> __sbh_alloc_new_region函数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#__sbh_alloc_new_group%E5%87%BD%E6%95%B0"><span class="nav-text"> __sbh_alloc_new_group函数</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#34-sbh%E8%A1%8C%E4%B8%BA%E5%88%86%E6%9E%90"><span class="nav-text"> 3.4 SBH行为分析</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%88%86%E9%85%8D"><span class="nav-text"> 分配</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#%E9%A6%96%E6%AC%A1%E5%88%86%E9%85%8D"><span class="nav-text"> 首次分配</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E7%AC%AC2%E6%AC%A1%E5%88%86%E9%85%8D"><span class="nav-text"> 第2次分配</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E7%AC%AC3%E6%AC%A1%E5%88%86%E9%85%8D"><span class="nav-text"> 第3次分配</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E7%AC%AC15%E6%AC%A1%E5%88%86%E9%85%8D%E9%87%8A%E6%94%BE"><span class="nav-text"> 第15次分配，释放</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8C%BA%E5%9D%97%E5%90%88%E5%B9%B6"><span class="nav-text"> 区块合并</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#freep"><span class="nav-text"> free(p)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%88%86%E6%AE%B5%E7%AE%A1%E7%90%86%E4%B9%8B%E5%A6%99"><span class="nav-text"> 分段管理之妙</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#35-vc6heap-state-reporting-functions"><span class="nav-text"> 3.5 VC6,Heap State Reporting Functions</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#36-vc-malloc-gcc-allocator"><span class="nav-text"> 3.6 VC malloc + GCC allocator</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#37-%E5%8F%A0%E5%BA%8A%E6%9E%B6%E5%B1%8B%E6%9C%89%E5%BF%85%E8%A6%81%E5%90%97"><span class="nav-text"> 3.7 叠床架屋，有必要吗？</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#4-%E7%AC%AC%E5%9B%9B%E8%AE%B2-lokiallocator"><span class="nav-text"> 4. 第四讲 loki::allocator</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#41-%E4%B8%8A%E4%B8%AD%E4%B8%8B%E4%B8%89%E4%B8%AAclasses%E5%88%86%E6%9E%90"><span class="nav-text"> 4.1 上中下三个classes分析</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#42-loki-allocator%E8%A1%8C%E4%B8%BA%E5%9B%BE%E8%A7%A3"><span class="nav-text"> 4.2 loki allocator行为图解</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#chunk"><span class="nav-text"> Chunk</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#chunkallocate"><span class="nav-text"> Chunk::Allocate()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#chunkdeallocate"><span class="nav-text"> Chunk::Deallocate()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#fixedallocatorallocate"><span class="nav-text"> FixedAllocator::Allocate()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#fixedallocatorvicinityfind"><span class="nav-text"> FixedAllocator::VicinityFind()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#fixedallocatordodeallocate"><span class="nav-text"> FixedAllocator::DoDeallocate()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#loki-allocator%E6%A3%80%E8%AE%A8"><span class="nav-text"> Loki allocator检讨</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#5-%E7%AC%AC%E4%BA%94%E8%AE%B2-other-issues"><span class="nav-text"> 5. 第五讲 other issues</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#51-gnu-c"><span class="nav-text"> 5.1 GNU C++</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#52-gnu-c%E5%AF%B9allocators%E7%9A%84%E6%8F%8F%E8%BF%B0"><span class="nav-text"> 5.2 GNU C++对allocators的描述</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#53-vs2013-span-stylecolorblue%E6%A0%87%E5%87%86span%E5%88%86%E9%85%8D%E5%99%A8%E4%B8%8Espan-stylecolorpurplenew_allocatorspan"><span class="nav-text"> 5.3 VS2013 标准分配器与new_allocator</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#54-g49-span-stylecolorblue%E6%A0%87%E5%87%86span%E5%88%86%E9%85%8D%E5%99%A8%E4%B8%8Espan-stylecolorpurplenew_allocatorspan"><span class="nav-text"> 5.4 G4.9 标准分配器与new_allocator</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#55-g49-malloc_allocator"><span class="nav-text"> 5.5 G4.9 malloc_allocator</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#56-g49-array_allocator"><span class="nav-text"> 5.6 G4.9  array_allocator</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#57-g49-debug_allocator"><span class="nav-text"> 5.7 G4.9 debug_allocator</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#58-g29%E5%AE%B9%E5%99%A8%E4%BD%BF%E7%94%A8%E7%9A%84%E5%88%86%E9%85%8D%E5%99%A8%E4%B8%8D%E6%98%AF-stdallocator-%E8%80%8C%E6%98%AF-stdalloc"><span class="nav-text"> 5.8 G2.9容器使用的分配器不是 std::allocator 而是 std::alloc</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#59-g49-__pool_alloc-%E7%94%A8%E4%BE%8B"><span class="nav-text"> 5.9 G4.9 __pool_alloc 用例</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#510-g49-bitmap_allocator"><span class="nav-text"> 5.10 G4.9 bitmap_allocator</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#5101-%E5%85%B3%E4%BA%8Eblockssuper-blocksbitmapmini-vector"><span class="nav-text"> 5.10.1 关于blocks，super-blocks，bitmap，mini-vector</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5102-1st-super-block%E7%94%A8%E7%BD%84%E5%90%AF%E5%8A%A8-2nd-super-block"><span class="nav-text"> 5.10.2 1st super-block用罄，启动 2nd super-block</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5103-2nd-super-block%E7%94%A8%E7%BD%84%E5%90%AF%E5%8A%A8-3rd-super-block"><span class="nav-text"> 5.10.3 2nd super-block用罄，启动 3rd super-block</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5104-1st-super-block-%E5%85%A8%E5%9B%9E%E6%94%B6"><span class="nav-text"> 5.10.4 1st super-block 全回收</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5105-2nd-super-block-%E5%85%A8%E5%9B%9E%E6%94%B6"><span class="nav-text"> 5.10.5 2nd super-block 全回收</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5106-3rd-super-block-%E5%85%A8%E5%9B%9E%E6%94%B6"><span class="nav-text"> 5.10.6 3rd super-block 全回收</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#511-%E4%BD%BF%E7%94%A8g49-%E5%88%86%E9%85%8D%E5%99%A8"><span class="nav-text"> 5.11 使用G4.9 分配器</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->
     
      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Maureen"
      src="/images/stan.jpeg">
  <p class="site-author-name" itemprop="name">Maureen</p>
  <div class="site-description" itemprop="description">心之所向，素履以往</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">7</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">7</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">2</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/maureenLiu" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;maureenLiu" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://blog.csdn.net/u011386173?spm=1000.2115.3001.5343" title="CSDN → https:&#x2F;&#x2F;blog.csdn.net&#x2F;u011386173?spm&#x3D;1000.2115.3001.5343" rel="noopener" target="_blank"><i class="crosshairs fa-fw"></i>CSDN</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:maureen@qq.com" title="E-Mail → mailto:maureen@qq.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
  </div>
  <div class="cc-license motion-element" itemprop="license">
    <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" class="cc-opacity" rel="noopener" target="_blank"><img src="/images/cc-by-nc-sa.svg" alt="Creative Commons"></a>
  </div>



      </div>

        <div id="music163player"> 
            <iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=86 src="//music.163.com/outchain/player?type=2&id=1475596788&auto=1&height=66"></iframe> 
        </div>
        <div class="back-to-top motion-element">
          <i class="fa fa-arrow-up"></i>
          <span>0%</span>
        </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 2021 – 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Maureen</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
      <span class="post-meta-item-text">站点总字数：</span>
    <span title="站点总字数">307k</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span class="post-meta-item-text">站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">4:39</span>
</div>

        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item" id="busuanzi_container_site_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  




  
<script src="/js/local-search.js"></script>













  

  


<script>
NexT.utils.loadComments(document.querySelector('#valine-comments'), () => {
  NexT.utils.getScript('//unpkg.com/valine/dist/Valine.min.js', () => {
    var GUEST = ['nick', 'mail', 'link'];
    var guest = 'nick,mail,link';
    guest = guest.split(',').filter(item => {
      return GUEST.includes(item);
    });
    new Valine({
      el         : '#valine-comments',
      verify     : false,
      notify     : false,
      appId      : '7A7ruXkEvS4VKjoTaajLunbw-9Nh9j0Va',
      appKey     : 'E4svxhhfVsrC9eCyM8YfT8uq',
      placeholder: "Just go go",
      avatar     : 'mm',
      meta       : guest,
      pageSize   : '10' || 10,
      visitor    : false,
      lang       : 'zh-cn' || 'zh-cn',
      path       : location.pathname,
      recordIP   : false,
      serverURLs : ''
    });
  }, window.Valine);
});
</script>

<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"log":false,"pluginJsPath":"lib/","pluginModelPath":"assets/","pluginRootPath":"live2dw/","tagMode":false});</script></body>
</html>

<!-- 页面点击小红心 -->
<script type="text/javascript" src="/js/clicklove.js"></script>
